首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >在Java中混淆同步的用法:模式还是反模式?

在Java中混淆同步的用法:模式还是反模式?
EN

Stack Overflow用户
提问于 2011-10-01 00:00:21
回答 5查看 1.1K关注 0票数 9

我正在对一个不属于我的Java产品进行代码审查。我不是Java专家,但我强烈怀疑这是毫无意义的,并表明了对同步工作方式的根本误解。

代码语言:javascript
代码运行次数:0
运行
复制
synchronized (this) {
    this.notify();
}

但我可能错了,因为Java不是我的主要游乐场。也许这样做是有原因的。如果你能告诉我开发人员在想什么,我将不胜感激。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-10-01 00:05:13

这当然不是没有意义的,您可以使用另一个线程,该线程引用了包含上述代码的对象

代码语言:javascript
代码运行次数:0
运行
复制
synchronized(foo) {
    foo.wait();
}

以便在发生事情时被唤醒。不过,在许多情况下,在内部/私有锁对象而不是this上进行同步被认为是一种好的实践。

然而,仅在同步块中执行.notify()可能是非常错误的-您通常有一些工作要做,并在完成时通知它,在正常情况下,这也需要在其他线程中自动完成。我们将不得不看到更多的代码来确定它是否真的是错误的。

票数 10
EN

Stack Overflow用户

发布于 2011-10-01 00:07:56

如果这就是同步块中的全部内容,那么它就是一个反模式,同步点是在块中做一些事情,设置一些条件,然后调用notifynotifyAll来唤醒一个或多个等待的线程。

使用wait和notify时,必须使用条件变量,请参见this Oracle tutorial

注意:始终在测试被等待条件的循环内调用wait。不要假设中断是针对您正在等待的特定条件,或者该条件仍然为真。

您不应该仅仅因为线程从对Object#wait的调用中退出就假定您收到了通知,原因有很多:

  • 当调用等待超时值的版本时,没有办法知道等待是由于接收到通知还是由于超时而结束。
  • 你必须考虑到线程在没有收到通知的情况下从等待中唤醒的可能性(“虚假唤醒”)。
  • 接收通知的等待线程仍然必须重新获取它在开始等待时放弃的锁,这两个事件之间没有原子链接;在收到通知和重新获取锁之间的时间间隔内,另一个线程可能会执行操作,并可能会更改系统的状态,从而导致通知现在无效。
  • 您可能会遇到这样的情况:通知线程在任何线程都在等待之前执行操作,从而导致通知无效。假设一个线程在另一个线程通知之前进入等待状态是危险的,如果你错了,等待线程将挂起indefinitely.

因此,通知本身还不够好,当等待/通知API没有为您提供足够的信息来了解发生了什么时,您最终会猜测通知是否发生了。即使通知线程正在做的其他工作不需要同步,更新条件变量也需要同步;至少应该更新synchronized块中的共享条件变量。

票数 3
EN

Stack Overflow用户

发布于 2011-10-01 00:07:38

这是非常好的。根据Java 6 Object#notify() api documentation的说法

此方法只能由此对象监视器的所有者线程调用。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7613027

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档