java 同步原语_Java为什么必须wait()始终处于同步块中

本文通过一个阻塞队列的例子,解释了在Java中如果不当使用wait()和notify()可能导致的死锁问题。在同步块外调用wait()可能会导致消费者线程错过生产者线程的通知,从而陷入僵局。解决方案是在synchronized块内使用wait()和notify(),以确保线程间的通信正确无误。这展示了Java并发编程中同步的重要性。
摘要由CSDN通过智能技术生成

小编典典

如果可以wait()在同步块之外调用并保留其语义-挂起调用者线程,可能造成什么损害?

让我们wait()用一个具体的例子来说明如果在同步块之外调用该函数会遇到什么问题。

假设我们要实现一个阻塞队列(我知道,API中已经有一个队列了:)

第一次尝试(没有同步)可能看起来像下面的样子

class BlockingQueue {

Queue buffer = new LinkedList();

public void give(String data) {

buffer.add(data);

notify(); // Since someone may be waiting in take!

}

public String take() throws InterruptedException {

while (buffer.isEmpty()) // don't use "if" due to spurious wakeups.

wait();

return buffer.remove();

}

}

这是可能发生的情况:

使用者线程调用take()并看到buffer.isEmpty()。

在使用者线程继续调用之前wait(),生产者线程会出现并调用full give(),即buffer.add(data); notify();

使用者线程现在将调用wait()(并且错过了notify()刚刚被调用的线程)。

如果运气不好,生产者线程将不会产生更多give()的结果,因为消费者线程永远不会醒来,而且我们陷入了僵局。

理解了问题之后,解决方案就显而易见了:用于synchronized确保notify在isEmpty和之间不调用wait。

无需赘述:同步问题是普遍的。正如Michael Borgwardt指出的那样,等待/通知完全是关于线程之间的通信的,所以你总是会遇到与上述情况类似的竞争状态。这就是为什么强制执行“仅在同步中等待”规则的原因。

@Willie发布的链接中的一段对其进行了很好的总结:

你需要绝对保证服务员和通知者就谓词的状态达成一致。服务员在进入睡眠之前的某个时候会稍稍检查谓词的状态,但是它的正确性取决于谓词在进入睡眠时是正确的。这两个事件之间存在一段时间的漏洞,这可能会破坏程序。

在上面的示例中,生产者和消费者需要达成共识的谓词buffer.isEmpty()。通过确保等待和通知在synchronized块中执行来解决协议。

2020-02-29

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值