锁池、等待池、notify详解

发布时间 2023-08-04 16:13:43作者: 风筝上的猫

线程状态图示

0

锁池和等待池

java中,每个对象都有两个池,锁池等待池
 
锁池:某个线程已经拥有了某个对象的锁,其他想要获取该对象的锁的线程就会进入该对象的锁池中;
⭕举例解释:
    假设线程A已经拥有了某个对象的锁(这里是对象 不是类),其他线程想要调用这个对象的某个synchronized方法或者块,因为这些线程在进入对象的synchronized方法之前必须先获取该对象锁的拥有权,但此时该对象的锁正被线程A所拥有,所以这些线程就进入了该对象的锁池中。
 
等待池:已经拥有某个对象的锁的线程调用了wait()方法,该线程将进入该对象的等待池去,等待池中的线程不竞争该对象的锁。
⭕举例解释:
    假设线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁(因为wait()方法必须出现在synchronized中,所以在执行wait()方法前线程A就拥有了该对象的锁),之后线程A就进入到了该对象的等待池中。
    如果其他一个线程调用了相同对象的notify()方法,那么会随机取出一个该对象等待池中的线程进入到该对象的锁池中;如果调用了相同对象的notifyAll()方法,那么处于该对象等待池中的所有线程就会全部进入该对象的锁池中,准备争夺锁的拥有权。
 
当执行该对象的notify()方法时,随机将等待池中的一个线程移到锁池中;当执行该对象的notifyAll()方法时,将等待池中的所有线程移到锁池中。
 
锁池中的线程可以竞争该对象的锁。
 

图示锁池和等待池

0
 
0
 

 

为什么wait、notify、notifyAll方法必须在synchronized中调用?

上述内容中我们知道,必须在synchronized方法中使用wait()方法、notify()及notifyAll()方法。为什么?
 
    wait 和 nodify 需要监视对其调用的 Object。
    JVM 在运行时会强制检查 wait 和 notify 有没有在 synchronized 代码中,如果没有的话就会报非法监视器状态异常(IllegalMonitorStateException),但这也仅仅是运行时的程序表象,那为什么 Java 要这样设计呢?其实这样设计的原因就是为了防止多线程并发运行时,程序的执行混乱问题
 
⭕举例解释:
    实现一个自定义阻塞队列。 这里的阻塞队列是指读操作阻塞,也就是当读取数据时,如果有数据就返回数据,如果没有数据则阻塞等待数据。
    如果 wait 和 notify 不强制要求加锁,那么在线程 1 执行完判断之后,尚未执行休眠之前,此时另一个线程添加数据到队列中。然而这时线程 1 已经执行过判断了,所以就会直接进入休眠状态,从而导致队列中的那条数据永久性不能被读取,这就是程序并发运行时“执行结果混乱”的问题。
此处引用稀土掘金作者(Java中文社群)文章,链接:https://juejin.cn/post/7067322092936495112。