一道Java的题目:java
关于sleep()和wait(),如下描述错误的一项是:线程
截取网上的一段话:cdn
全部对象都自动含有单一的锁。
JVM负责跟踪对象被加锁的次数。若是一个对象被解锁,其计数变为0。在任务(线程)第一次给对象加锁的时候,计数变为1。每当这个相同的任务(线程)在此对象上得到锁时,计数会递增。
只有首先得到锁的任务(线程)才能再次加锁(锁的重入)。
每当任务离开一个synchronized(同步)方法,计数递减,当计数为0的时候,锁被彻底释放,此时别的任务就可使用此资源。对象
虽然java底层使用队列实现的,可是用池来描述会更容易理解,后面会看到blog
在Java中,每一个对象都有两个池,锁(monitor)池和等待池队列
锁池:假设线程A已经拥有了某个对象的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),因为这些线程在进入对象的synchronized方法以前必须先得到该对象的锁的拥有权,可是该对象的锁目前正被线程A拥有,因此这些线程就进入了该对象的锁池中。资源
等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁(由于wait()方法必须出如今synchronized中,这样天然在执行wait()方法以前线程A就已经拥有了该对象的锁),同时线程A就进入到了该对象的等待池中。
若是另外的一个线程调用了相同对象的notifyAll()方法,那么处于该对象的等待池中的线程就会所有进入该对象的锁池中,准备争夺锁的拥有权。若是另外的一个线程调用了相同对象的notify()方法,那么仅仅有一个处于该对象的等待池中的线程(随机)会进入该对象的锁池.同步
若是线程调用了对象的 wait()方法,那么线程便会释放锁进入该对象的等待池中,等待池中的线程不会去竞争该对象的锁。 当有线程调用了对象的 notifyAll()方法(唤醒全部 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。 优先级高的线程竞争到对象锁的几率大,倘若某线程没有竞争到该对象锁,它还会留在锁池中,惟有线程再次调用 wait()方法,它才会从新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。it
注:wait() ,notifyAll(),notify() 三个方法都是Object类中的方法.io
public final void wait() throws InterruptedException,IllegalMonitorStateException
该方法用来将当前线程置入休眠状态,直到接到通知或被中断为止。在调用 wait()以前,线程必需要得到该对象的对象级别锁,即只能在同步方法或同步块中调用 wait()方法。进入 wait()方法后,当前线程释放锁。在从 wait()返回前,线程与其余线程竞争从新得到锁。若是调用 wait()时,没有持有适当的锁,则抛出 IllegalMonitorStateException,它是 RuntimeException 的一个子类,所以,不须要 try-catch 结构。
public final native void notify() throws IllegalMonitorStateException
该方法也要在同步方法或同步块中调用,即在调用前,线程也必需要得到该对象的对象级别锁,的若是调用 notify()时没有持有适当的锁,也会抛出 IllegalMonitorStateException。
该方法用来通知那些可能等待该对象的对象锁的其余线程。若是有多个线程等待,则线程规划器任意挑选出其中一个 wait()状态的线程来发出通知,并使它等待获取该对象的对象锁.
这里有两个注意点:
1.notify 后,当前线程不会立刻释放该对象锁,wait 所在的线程并不能立刻获取该对象锁,要等到程序退出 synchronized 代码块后,当前线程才会释放锁,某一个wait所在的线程也才能够获取该对象锁 但不惊动其余一样在等待池中等待被notify的线程们。
2.当第一个得到了该对象锁的 wait 线程运行完毕之后,它会释放掉该对象锁,此时若是该对象没有再次使用 notify 语句,则即使该对象已经空闲,其余 wait 状态等待的线程因为没有获得该对象的通知,会继续在等待池中,阻塞在 wait 状态,直到这个对象发出一个 notify 或 notifyAll。
这里须要注意:等待池中的线程们等待的是被 notify 或 notifyAll,暂时还不是锁。这与下面的 notifyAll()方法执行后的状况不一样。
public final native void notifyAll() throws IllegalMonitorStateException
该方法与 notify ()方法的工做方式相同,重要的一点差别是:
notifyAll 使全部原来在该对象上 wait 的线程通通退出 wait 的状态(即所有被唤醒,从等待池移动到锁池,再也不等待 notify 或 notifyAll,但因为此时尚未获取到该对象锁,所以还不能继续往下执行),变成在锁池中等待获取该对象上的锁.
一旦该对象锁被释放(notifyAll 线程退出调用了 notifyAll 的 synchronized 代码块的时候),他们就会去竞争。若是其中一个线程得到了该对象锁,它就会继续往下执行,在它退出 synchronized 代码块,释放锁后,其余的已经被唤醒的线程将会继续竞争获取该锁,一直进行下去,直到全部被唤醒的线程都执行完毕。
最开始的那道题答案是D,notifyAll()也能够