首页 > 解决方案 > 关于并发的问题

问题描述

如果我理解正确同步应该足以确保一次只有一个线程可以访问资源:

当一个线程想要执行一个同步块时,它会获取监视器并在同步块结束时自动释放它,同时所有其他尝试访问监视器已经被持有的同步块的其他线程都被放入队列中并只要程序正在运行,它将继续尝试访问同步方法。

如果我在同步块内调用 wait(),那么我最终可能会在同步块内有多个线程,并且我也被迫在块末尾调用 notify() 以避免线程永远等待的情况。

标签: javamultithreadingconcurrency

解决方案


首先,我刚才说的对吗?如果不是,那有什么问题?

前两段恰到好处。关于等待/通知的第三段大部分是正确的。不过有几点:

  • 某些线程需要调用notifyor notifyAll。但它不一定是这个。
  • 您可以在任何时候调用,而不仅仅是在块的末尾。无论哪种方式,在当前线程离开块之前都不会发生通知。
  • 等待从未到达的通知的线程不一定永远卡住。例如,线程中断将导致waitInterruptedException.

如果是,最常见的情况synchronized应该与wait()和一起使用是notify()什么?

“应该”这个词是一个加载词。您可以使用wait()的情况notify()是一个线程需要等待某个事件发生的情况。(通常这用于实现条件变量。)但根据具体情况,可能有更好的方法来做到这一点。

此外,您不能使用wait()notify() 持有关联的互斥锁。(如果你尝试这样做,你会得到一个例外!)


一般来说,如果我通过添加wait()notify()来使代码更复杂synchronized,那么使用更复杂的工具会更好ReentrantLocks吗?

一般不会。

如果有更高级别的并发类可以执行您尝试执行的操作,则通常最好使用它们而不是原始互斥锁 + 等待/通知。但情况并非总是如此。

你提到了ReentrantLock。这个类实际上只是“在 steriods 上”的类似互斥锁。它们有一些原始互斥锁不具备的功能(例如tryLock查看哪些线程正在等待),但是如果您不需要ReentrantLock额外的功能,那么使用原始互斥锁并没有真正的优势。(一个可能的缺点Lock类不会在退出块时自动释放。所以你真的需要将它们与资源结合使用try ... finallytry


推荐阅读