在此声明:以下文章转载自sleep & wait | notify | notifyAll在此表示感谢!虽说两篇文章中我有不同见解,但为了尊重版权,在此全部转载,只是去掉了各自文中的重复部分,在此再次表示感谢!
一、sleep & wait
1、两者来自不同的类(分别是Thread和Object)
2、sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或方法
3、wiat只能在同步控制方法或者同步控制块使用,而sleep可以在任何地方使用
4、sleep必须捕获异常,而wait不需要
二、wait和notify为什么会封装在Object类中,而不是像sleep方法在Thread中?
wait和notify的本质是基于条件对象,而且只能由已经获得锁的线程调用。java的每个Object都有一个隐式锁,这个隐式锁关联一个Condition条件对象,线程拿到这个隐式所(比如进入synchronized代码区域),就可以调用wait,语义是Condition条件对象上等待,其他的线程可以在这Condition条件对象上等待 ,等满足条件之后,就可以调用notify或者notifyAll来唤醒所有在此条件对象上等待的线程。
三、死锁
1、互斥条件:一个资源每次只能被一个进程使用;
2、部分分配条件:允许线程或进程获得所需的部分条件;
3、不剥夺条件:进程已获得的资源,在未使用完之前,不能强制剥夺;
4、环路条件:若干进程之间形成一种头尾相接的循环资源关系。
这四个条件时死锁的必要条件,只有系统发生死锁,这些条件必然成立,只要上述条件之一不满足,就不发生死锁。
四、常识
1、在java中所有线程都是同时启动的,至于什么时候,哪个先执行,完全看谁先得到CPU的资源。
2、在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾回收线程。因为每当使用java命令执行一个类的时候,实际上启动了一个jvm,每个jvm其实就是在操作系统中启动了一个线程
3、理解java编译器的线程处理和jvm。有助于编程高效、性能更好的java代码。
五、java中wait/notify机制
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。notify()方法和wait()方法的基本思想是给方法或代码块提供一种相互通信的方式,而这些方法或者代码块同步于某个特定对象。代码块可以调用wait()方法来将自身的操作挂起,直到同一个对象上的其他同步方法或同步代码块以某种方式将其改变,并调用notfiy()方法来通知此代码块改变已经完成。一个线程一般会因为它所同步的对象的某个属性没有设置,或者某个条件没有满足而调用wait()方法,这些由另一个线程的动作决定。最简单的情况可能是资源因为正被另一个线程修改而繁忙,还有其他的可能情况。
通常,多线程之间需要协调工作。例如,浏览器的一个显示图片的线程displayThread想要执行显示图片的任务,必须等待下载线 程 downloadThread将该图片下载完毕。如果图片还没有下载完,displayThread可以暂停,当downloadThread完成了 任务 后,再通知displayThread“图片准备完毕,可以显示了”,这时,displayThread继续执行。
以上逻辑简单的说就是:如果条件不满足,则等待。当条件满足时,等待该条件的线程将被唤醒。在Java中,这个机制的实现依赖于wait/notify。等待机制与锁机制是密切关联的。例如:
synchronized(obj) {while(!condition) {obj.wait();}obj.doSomething();}
当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait()。
在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A:
synchronized(obj) {condition = true;obj.notify();}
需要注意的概念是:
1、调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {...} 代码段内。
2、调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {...} 代码段内唤醒A。
3、当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。
4、如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。
5、obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。
6、当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。
六、join
join方法的功能就是使异步执行的线程变成同步执行。也就是说,当调用线程实例的start方法后,这个方法会立即返回,如果在调用start方法后后需要使用一个由这个线程计算得到的值,就必须使用join方法。如果不使用join方法,就不能保证当执行到start方法后面的某条语句时,这个线程一定会执行完。而使用join方法后,直到这个线程退出,程序才会往下执行。例如:你准备洗澡,需要准备的步骤,准备好衣服,沐浴的东西及烧水这些事情,由于烧水耗时太长,如果也放在主线程之中,就很浪费资源,所以如果我们另开线程去处 理,就会达到很好效果,于是乎在准备好衣服,沐浴的东西之前就去开子线程烧水,烧水的过程中主线程准备好衣服,沐浴的东西,此时就等待水烧好,然后方可痛 快的洗澡了!
在此声明:以下文章转载自 sleep & wait | notify | notifyAll在此表示感谢!虽说两篇文章中我有不同见解,但为了尊重版权,在此全部转载,只是去掉了各自文中的重复部分,在此再次表示感谢!