00:00
哎,下个内容呢,叫线程的通信,嗯,一看这个标题呢,好像这个是挺大一个事儿,实际上呢,不是就是像我们这个,嗯,这是一个共享数据,这呢是一个线程,这呢是一个线程,这两个线程呢,都来操作这个共享数据,他们之间呢,如果有某种这个,呃,这个算是交流吧,这种交流是我们加上这个引号的交流啊,那这呢就都可以算成交通信了,比如说呢,我们马上要写的一个例子,就是说我们这儿呢,打印一下一到100这100个数,打印的时候呢,我们要求呢,这两个线程呢,交替打印。就是这个线程打印个一,打印完以后呢,这个一你就别再往下打了,二的话呢,必须由我们这个线程来打,然后三的话呢,你再打,四呢,你再打,就是你一下我一下,你一下我一下,这呢就算是一个交流啊,我们把这个呢就称作叫线程的通信啊,那不妨呢,咱们就诶先通过这个例子,咱们说明一下该如何去实现线程的通信,这里边儿呢,就会涉及到几个方法的使用,所以线程的通信呢,其实就是几个方法的使用啊,就没有大家想的时候那么那么严重了,就啊它的难度的话呢,比我们讲的同步呢是要低的,那我们就以这个题目为例,CTRLC来写一下,嗯,这块收起来,这块收起来,这块也不少了,再来一个。
01:17
嗯,新建一个包,这个呢,我们就,呃,直接我就写个叫JAVA2了。嗯,这呢,咱们就是来打这个100以内的这个自然数了,所以我这就写成一个叫呃number的。或者我就写线程通信吧,Communication的一个测试这样。哎,这呢是咱们一个线程通信的一个例子,哎这个例子的话呢,就是做这个事儿,诶看一下该怎么去做,那这个两个线程,这呢又涉及到线程的创建继承实现都可以,然后呢,打印一到100交替呢打印好这呢咱们去写一个class,比如这叫一个number。
02:05
Number不,咱们用一下这个实线吧,实现的话呢,我们实现runable,嗯,在这al enter回车,回车去重写我们这个run方法,嗯,两个线程回头我们在这里边呢,去造一下这俩线程,嗯,两个线程的话呢,去调用这run方法的时候呢,让他们去打印一下一到100,这呢其实也相当于他们的一个共享数据了,所以我在这个位置呢,Private声明一个int型的叫number,开始呢,就是一开始就是一,然后在这个循环在这个这个run当中。这里边儿你还得写一个well。哎,写个for也行啊,只是说呢,你这个具体的循环的这个终止条件,你不能指明说一人各50次了,就写成个处就行,在这里边儿呢,我们去判断一下,说如果这个number,嗯,只要你是小于,小于嗯,要不要等于啊,那先看你里边咋写的,这里边呢,我们直接呢一过来呢,就先打一下这个I呗。
03:09
那这呢,打印我们也打印一下是谁输出的,所以呢,来一个thread.current thread name,然后冒号一下,后边呢,我们打一下这个number。打印number,那比如说呢,你这是一一进来的时候呢,我们就打印了一,然后这个呢,要不要100呢,还得要对100的时候呢,也得出来,所以加上这个等号,嗯,这个输入完以后呢,这个number呢,再加加一下就可以了,然后呢,这来一个else,整一个break。哎,这就成了,嗯,这是咱们这个run方法这块,然后呢,在我们这个测试类当中写一个may,呃,我们首先呢,先去new一个number对象。奥塔。然后我们去NEW2个线程。
04:06
哎,Al enter t12个,哎,然后分别的给它们起个名字。线程一啊,线程二。哎,接下来呢,让他们去start。嗯,好,这就可以了,那么这个时候呢,咱们去让他们执行的时候呢,这个也相当于是一个共享数据了,诶这个共享数据的话呢,同样呢,也会出现的安全问题了,这个呢就不用多说了啊,诶只要操作这个共享数据,这个时候呢,它就会有这个安全的问题啊,那出现安全问题呢,咱们就得解决这个安全问题,得把这个共享数据呢,呃,这个代码呢,我们得给它包起来啊,那这里边呢,咱们就直接呢使用这个同步代码块来处理一下了,把它呢包起来,哎,刚才说的这个快捷键呢,叫。
05:05
嗯,Out shiftd z这呢,我们选一个这个位置呢写谁。比较简单的写谁啊,这次可以吧,可以的,那这时候呢,就是唯一的这个number对象,好,嗯,这个呢,你可以顺便呢,给它加上一个这个sleep呀,其实都可以。嗯,咱们加sleep呢,只是说让这个如果有安全问题的话呢,就暴露的概率更大一些,那你现在都已经安全了,其实加不加,让他所谓的暴不暴露就都无所谓了啊,你要想让它打印的慢一点,那你就加上一个这个sleep比十毫秒啊,挺棒的了啊,然后al enter,哎,叉开处理一下这个异常。哎,这就行了,那目前的话呢,咱们,呃,看不到他们这种交替的情况,比如说咱们执行一下你看看。你看没有是吧,嗯,这个呢,都是先乘一啊。
06:01
还真是。我们写的有问题吧,没事,嗯,下边这个名写成二对着呢啊。还是是吧。还是那就还是吧,反正咱们写的是没事没问题。啊,那现在呢,咱们让它交替起来,这不就强制的说你这个线程音,你别老你打印啊,我们这个线上呢也得打印,这呢就体现了一个叫这个通信的问题,那通信咱们怎么做这个事儿呢。看一下啊,这个西奈的话呢,我这写的是个Z次,Z次的话呢,我们一进来判断一下这个是不是小于等于100,哎,如果满足的话呢,我们这块呢,就做了一个输出,做了一个加加加加完以后,如果是我们这个线程一,他先打印的这个数一,他打印完这个一以后,我们这时候是不是就让他应该阻塞一下。
07:02
哎,因为只有线程一阻塞了,是不是线程二才可能进来,哎,我们就让它阻塞,此时呢,咱们要用一个方法,这个方法呢,就叫做wait方法。诶,就叫wait方法,这个方法本身呢,有异常,咱们al一下给大家处理一下。啊,这个胃呢,就是咱们讲线程的生命周期的时候。哎,在这的时候呢,这不是我写了一下这个wait嘛,哎,就是当一个线程运行的时候呢,我们1WAIT它就进入阻塞了。哎,怎么就这个恢复这个这个到就绪状态呢,去调这两个方法才行,哎得这么着啊,那现在的话呢,我这加了一个wait就是呃,使得。使得调用如下wait方法的线程,哎,进入阻塞状态。啊,就成这样了,那好了,我们那个线程一假设先进来,进来以后呢,它就输出了一下一,然后呢,它就wait了。
08:08
如果这个代码呢,我目前就去执行的话,你像他wait了,我们还没有让他去想办法去结束阻塞,那限制二的话呢,进来以后是不是也打这个数,马上也就wait了啊,那接下来呢,这个。是不是就都阻塞到这儿就停止不不走了,嗯,你看看。就成这样了,哎,这个呢,你看接受不了,这个我们得给它显示的先点一下啊,那么这样呢,光用wait显然不行,还得去搭配另外的方法来用,嗯,那另外的方法呢,就叫做naughtyify,那写到哪呢?写到哪呢?你可以写到我们这个,哎,Size的这个里边,就是一进来的时候呢,我这个位置,比如我加一个叫natyify加notify还是not,还是加了一个notify哦,这就涉及到唤醒一个还是唤醒很多个的问题。
09:02
哎,咱们这个题目当中就只有两个线程,哎甲呃,线程一呢,把线程二唤醒,线程二呢可以去唤醒,线程一就这里啊,所以你就用notify就行,如果回头咱们有三个线程。有三个线程,其中两个呢,都被not,都被wait了啊,你通过第三个线程,你要是调notify all的话呢,就可以把这两个都唤醒,All就是所有的啊,你要调notify呢,它只能唤醒一个,那就看谁的优先级高啊,谁的优先级高就唤醒谁,那要一样的话,那就相当于随机唤醒一个了。啊行,那这呢,你写这个all还不写哦,都一样,因为总之现在就只有他俩了啊,我写个notify吧。行,我这加了个notify,那此时这个代码是什么意思呢?比如说一开始的时候,这个一进来,假设是线程一抢到了,这时候notify呢,其实没什么意义了,因为也没有wait的线程。啊,那也就是只是执行了一下而已啊,那么这个线程一的话呢,把这个一这个数打印出来了,他wait了,然后线程二进来,线程二一进来我就先闹换,那么我们这个线程二是不是就把这个线程一给它唤醒了。
10:11
对啊,就唤醒了,唤醒以后注意,虽然我这时候把这个线程一唤醒了,但是呢,我们线程二是不是现在拿着这个同步健身器了,所以呢,虽然你一醒了,但是你一也进不来,因为我这时候二握着这个锁呢,哎,那就接着我们这二呢,把这个二这个数就输出了,二输出完以后呢,它线程二呢,就wait了啊它就wait了,这个时候wait呢,还有一个点就是一旦执行wait呢,这个会释放锁。这个位呢会释放锁,因为只有我们这个线程二,它释放了锁,这个一因为人家醒着呢,一是不是才可以进来。在这一点上跟谁不一样啊?跟他不一样吧。Sleep咱们说了,咱们举例子说你去厕所里了,然后呢,你在里边假设一不小心睡着了,是不是,那个门也不会说你一睡着门自动开了是吧?诶门不就咱们相内那个同步监视器嘛,啊,你就是睡着了,那个锁还是锁着的,也就是说呢,这个sleep呢?哎,当你掉这个sleep的时候,虽然这个线程的阻塞了,但是它不会释放锁,而这个weight不一样,一旦WEIGHT1执行,它就把锁给释放了,所以说我们这个线程二呢,哎,它这时候呢,进入阻塞状态,它把锁一释放,他一释放一不就拿到了,一拿到以后呢,一一进来,一一进来呢,1FI不就把二给唤醒了吗?
11:35
哎,那我一进来呢,唤醒了二了,但是我一还拿着这个锁呢,所以二呢你也进不来,我一呢就把这个三打印了,三打印完以后,三一又wait了啊右翼是往左二就进来了,这样这不就交替了吗,来执行。哎,大家看这个结果。这呢就是一个交替打印,哎没问题,那这呢就是咱们这道问题的一个解决方案啊,那这里边呢,我们提到了这个两个方法,一个呢叫wait方法,一个呢叫notify方法,这呢就涉及到我们线程通信的三个方法涉及到的。
12:17
三个方法啊,三个方法首先呢,我们提到一个叫wait的方法,哎,然后另外呢,一个叫notify,哎,还有呢叫nottyify or,那这三个方法首先呢,我们来说一下这个wait方法。哎,这个位的方法啊,那么我们说的一旦呃执行此方法,那么当前线程就呃进入阻塞状态。哎,并对啊释放啊释放,咱们就同步监视器吧。诶,并释放同同步监视器,那这时候呢,就意味着你其他的线程呢,是可以,诶拿到这个同步监视器,接着呢,进入我们的呃同步代码块当中的啊哎,这个大家关注一下它这个notify呢,还说一旦执行此方法。
13:10
啊,就会唤醒,哎,被wait的。啊,一个线程啊,那我们说如果有多个线程被V呢,哎,我们就唤醒啊,优先级高的那个啊,高的啊那个啊,总之呢,就是我们这个notify呢,只能唤醒一个啊,而notify all呢说一旦执行此方法,就会唤醒所有被wait的线程。哎,这个notify的区别呢,就是一个是唤醒一个,一个是唤醒,所有的比较简单一些啊好这呢,我们就是关于这三个方法的使用,那这里边呢,需要有几个注意点,咱们下边说明一下,诶第一个注意点,第一个什么注意点呢?我们说wait notify和notify or这三个方法呢,是涉及到叫线程通信当中的三个方法,那线程通信中的这三个方法,我们说它有一个使用的前提,那就是只能够是出现在同步代码块或者是同步方法当中。
14:25
哎,大家会看到我这写的,你看这个notify和这个wait方法,我是不是都把它写在这个同步代码块里了。哎,它的使用前提呢,就是这些方法的调用呢,都得在同步代码块或者是同步方法当中,你用那个lock都不可以。哎,Log的方式呢,你要想实现通信不是用的这种方式啊,哎,那这里边儿我们说明一下这个wait。然后notify。Notify all啊,这三个方法。
15:01
哎,三个方法说必须使用在,哎,就是他们来表示线程通信的时候,必须呢,使用在同步代码块或同步方法中啊,这个lock的话呢,要想使用线程通信,它有别的方式啊,这块暂时呢,大家就先不用掌握了啊,咱们就忽略就不说了啊,这三个方法都必须使用在同步代码块或同步方法中,好,这是第一个问题,第二问题。第二个问题,大家看我这时候的notify和notify all,呃和这个wait,我前面呢,没有说是谁掉的。没加对象点,那么大家想一下这个谁掉的?哎,对,你肯定是Z掉的吧。凡是咱们这个省略的,那你就看你这是不是静态了,那要是不是静态的,那就肯定是省略这次了,你要是静态方法呢,是不是就省略累点了,哎,这咱们面向对象都说过的,那就意味着我们这个wait notify前边都省的是this啊,This我这也写this了。
16:12
然后呢,这个这次其实代表的都是这个number的对象啊,Number对象呢,在这儿充当的是同步监视器啊,这样掉了,哎,加上这次以后一运行啊,肯定没毛病。啊,这还是一个对的啊成,那我们还想说一个什么事呢,咱们前面讲这个同步监视器的时候呢,说过这个监视器可以是任何一个对象来充当,只要你是唯一的就可以了,那咱们这块呢,比如我显示的再去定义一个object。诶定义了一个object,然后呢,我这个object呢,是可以充当这个同步监视器的,没问题吧,没问题,好我把这个OB呢写到这以后,这个呢还用的是Z次,这时候我们跑一下。你看挂了。
17:01
叫非法的monitor state exception。啊,这个错误的原因是什么呢?就是它俩不一致了。他俩不一致了。言外之意啊,我们这里边儿的这三个方法的调用者必须是同步代码块,或者是同步方法当中的同步监视器。啊,这要是注意一下啊,第二个问题说这三个方法的调用者。哎,调用者,哎,必须是同步代码块或同步方法中的。哎,同步监视器。啊,正因为是有这样要求,所以说咱们同步监视器就是在这俩里边才有嘛,所以我们这仨方法才只能在这两种情况下去用啊,必须呢是有我们这个同步监视器发起的调用,否则。
18:04
哎,我们说会出现刚才的这个异常。哎,这个异常好,那为了保证这个代码呢正确,那咱们可以把这个Z呢改成obj。看这个。哎,改成五笔记,哎改完以后呢,我们再跑一下。哎,这就OK了。哎,这就OK了。好,那么接着顺着再往下说啊,这三个方法呢,咱们现在是在线程通信当中去讲呢,很多同学呢,会误以为这三个方法呢,是在thad类里边定义的。因为咱们讲现场才说到这三个方法,但事实上呢,这三个方法不是定义在类里的。哎,是定义在哪呢?哎,这三个方法我们说呢,是定义在object类当中的。
19:05
Java点儿浪包下的object这个类种。为什么呢?你看哈,咱们说这个叫同步监视器,同步监视器是不是可以说任何一个类的对象都可以充当。任何一个类的对象都可以充当,那么只要你拿了一个类的对象,这当成同步监视器了,我这个位置是不是一定要拿这个对象去调这个方法,那得保证咱们任何一个对象都得有这个方法。既然任何一个对象都得有这个方法,是不是就放在我们这当中啊,你看我这个逻辑是很严密的是吧?哎,所以说呢,我们这个notify呀,V呀,A,它们都定义在object当中,哎,就是方便呢,你让任何一个对象呢,去充当这个同步监视器的时候呢,能够去调这个notify和V。哎,站长就说清楚了。
20:00
啊,那么关于线程通信呢,就涉及到这样的三个方法啊,这个先停一下。
我来说两句