190227-Java的锁池与对象池

Java的锁池与对象池

前言

在Java程序的开发或者学习,常常遇到各种各样的锁,因为有内置锁的机制,每个对象都可以承担锁的功能

对象池与锁池

Java虚拟机会为每个对象维护两个“队列”(姑且称之为“队列”,尽管它不一定符合数据结构上队列的“先进先出”原则):一个叫Entry Set(入口集),另外一个叫Wait Set(等待集)。

锁池:

对于任意的对象objectX,objectX的Entry Set用于存储等待获取objectX这个锁的所有线程,也就是传说中的锁池

对象池:

objectX的Wait Set用于存储执行了objectX.wait()/wait(long)的线程,也就是等待池。

具体解释

线程状态图

锁池

  1. 假设objectX是任意一个对象,假设有线程A、B、C同时申请objectX这个对象锁
  2. 那么由于任意一个时刻只有一个线程能够获得(占用/持有)这个锁,因此除了胜出(即获得了锁)的线程(这里假设是B)外,其他线程(这里就是A和C)都会被暂停(线程的生命周期状态会被调整为BLOCKED),这些因申请锁而落选的线程就会被存入objectX对应的锁池之中。
  3. 当objectX被其持有线程(这里就是B)释放时,锁池中的一个任意(注意是“任意”,而不一定是锁池中等待时间最长或者最短的)线程会被唤醒(即线程的生命周期状态变更为RUNNABLE)
  4. 这个被唤醒的线程会与其他活跃线程(即不处于锁池之中,且线程的生命周期状态为RUNNABLE的线程)再次抢占objectX
  5. 被唤醒的线程如果成功申请到objectX,那么该线程就从锁池中移除。否则,被唤醒的线程仍然会停留在锁池中,并再次被暂停,以等待下次申请锁的机会

对象池

  1. 如果有个线程执行了objectX.wait(),那么该线程就会被暂停(线程的生命周期状态会被调整为Waiting),并且会释放掉objectX锁,然后被存入objectX的等待池之中
  2. 此时,该线程就被称为objectX的等待线程
  3. 当其他线程执行了objectX.notify()/notifyAll()时,等待池中的一个(或者多个,取决于被调用的是notify还是notifyAll方法)任意(注意是“任意”,而不一定是等待池中等待时间最长或者最短的)等待线程会被唤醒,这些被唤醒的线程会被放到锁池中,会与锁池中已经存在的线程以及其他(可能的)活跃线程共同参与抢夺objectX。
  4. 至于代码中到底是使用notify还是notifyAll方法,这个要根据实际情况来分析。
  5. 如果另外的一个线程调用了相同对象的notifyAll()方法,那么处于该对象的等待池中的线程就会全部进入该对象的锁池中,准备争夺锁的拥有权。如果另外的一个线程调用了相同对象的notify()方法,那么仅仅有一个处于该对象的等待池中的线程(随机)会进入该对象的锁池。

PS:等待池中的线程被notify()或者notifyAll()方法唤醒进入到锁池,最后竞争到了锁并且进入了Runnable状态的话,会从wait现场恢复,执行wait()方法之后的代码

参考资料

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×