先说两个概念:锁池和等待池.net
锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),因为这些线程在进入对象的synchronized方法以前必须先得到该对象的锁的拥有权,可是该对象的锁目前正被线程A拥有,因此这些线程就进入了该对象的锁池中。
等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池中。线程
而后再来讲notify和notifyAll的区别对象
若是线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
当有线程调用了对象的 notifyAll()方法(唤醒全部 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的全部线程移动到锁池中,等待锁竞争
优先级高的线程竞争到对象锁的几率大,倘若某线程没有竞争到该对象锁,它还会留在锁池中,惟有线程再次调用 wait()方法,它才会从新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。blog
综上,所谓唤醒线程,另外一种解释能够说是将线程由等待池移动到锁池,notifyAll调用后,会将所有线程由等待池移到锁池,而后参与锁的竞争,竞争成功则继续执行,若是不成功则留在锁池等待锁被释放后再次参与竞争。而notify只会唤醒一个线程。队列
有了这些理论基础,后面的notify可能会致使死锁,而notifyAll则不会的例子也就好解释了进程
https://blog.csdn.net/djzhao/article/details/79410229开发
==========同步
sleep()是使线程暂停执行一段时间的方法。wait()也是一种使线程暂停执行的方法。例如,当线程执行wait()方法时候,会释放当前的锁,而后让出CPU,进入等待状态。而且能够调用notify()方法或者notifyAll()方法通知正在等待的其余线程。notify()方法仅唤醒一个线程(等待队列中的第一个线程)并容许他去得到锁。notifyAll()方法唤醒全部等待这个对象的线程并容许他们去竞争得到锁。具体区别以下:it
1) 原理不一样。sleep()方法是Thread类的静态方法,是线程用来控制自身流程的,他会使此线程暂停执行一段时间,而把执行机会让给其余线程,等到计时时间一到,此线程会自动苏醒。例如,当线程执行报时功能时,每一秒钟打印出一个时间,那么此时就须要在打印方法前面加一个sleep()方法,以便让本身每隔一秒执行一次,该过程如同闹钟同样。而wait()方法是object类的方法,用于线程间通讯,这个方法会使当前拥有该对象锁的进程等待,直到其余线程调用notify()方法或者notifyAll()时才醒来,不过开发人员也能够给他指定一个时间,自动醒来。io
2) 对锁的 处理机制不一样。因为sleep()方法的主要做用是让线程暂停执行一段时间,时间一到则自动恢复,不涉及线程间的通讯,所以,调用sleep()方法并不会释放锁。而wait()方法则不一样,当调用wait()方法后,线程会释放掉他所占用的锁,从而使线程所在对象中的其余synchronized数据能够被其余线程使用。
3) 使用区域不一样。wait()方法必须放在同步控制方法和同步代码块中使用,sleep()方法则能够放在任何地方使用。sleep()方法必须捕获异常,而wait()、notify()、notifyAll()不须要捕获异常。在sleep的过程当中,有可能被其余对象调用他的interrupt(),产生InterruptedException。因为sleep不会释放锁标志,容易致使死锁问题的发生,所以通常状况下,推荐使用wait()方法。————————————————版权声明:本文为CSDN博主「种向日葵的小仙女」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处连接及本声明。原文连接:https://blog.csdn.net/qiuchaoxi/article/details/79837568