Java监视器中同一对象调用入队出队方法是否会引发死锁
核心问题解答
1. 入队出队可以交由同一个类转发调用
你完全可以把两个方法的调用入口封装到同一个类中,通过该类转发入队、出队请求,这个调整本身不影响队列的并发逻辑,是合理可行的。
2. 不会出现你担心的死锁问题
你顾虑的「出队线程卡在await调用时阻止入队,导致队列停转」的情况不会发生,这是Javajava.util.concurrent.locks包下Lock和Condition的固有语义决定的:
- 当线程调用
Condition.await()方法时,会自动释放当前持有的关联Lock锁(也就是你的tasksLock),之后该线程进入Condition的等待队列,不再持有锁资源 - 此时其他发起入队请求的线程可以正常获取
tasksLock,完成元素插入、唤醒等待线程的全流程,不会被卡在await的线程阻塞 - 等待的出队线程被
signal()唤醒后,会自动重新尝试获取tasksLock,拿到锁后会从await()调用的位置恢复执行,继续后续的出队逻辑
Java中锁的调度是线程维度的,和你通过哪个类来调用队列的方法没有任何关系。只要入队、出队操作是由独立的线程发起,哪怕走同一个类的转发入口,也不会出现互相阻塞导致队列完全停止的问题。
额外提示:你提供的示例代码存在几处明显的笔误,正式使用前需要修复,否则会直接出现编译错误或逻辑问题:
getNextTask方法中(!placeholder_check())前缺少if关键字- 你错误地将
Condition类型的成员变量newTask赋值为出队的Task元素,属于类型不匹配错误,需要单独声明局部Task变量来接收出队结果 getNextTask方法没有在finally块中释放tasksLock,如果await或者出队操作抛出异常,会导致锁永远不被释放,引发真正的死锁。正确写法是将lock()之后的所有逻辑包裹在try代码块中,在finally代码块中调用tasksLock.unlock()addNextTask方法中调用signal()的变量名写错,你定义的Condition变量名是newTask,不是newAnyTask
内容的提问来源于stack exchange,提问作者kwdrt
相关产品推荐
相关产品推荐

