java - 关于并发的问题
问题描述
如果我理解正确同步应该足以确保一次只有一个线程可以访问资源:
当一个线程想要执行一个同步块时,它会获取监视器并在同步块结束时自动释放它,同时所有其他尝试访问监视器已经被持有的同步块的其他线程都被放入队列中并只要程序正在运行,它将继续尝试访问同步方法。
如果我在同步块内调用 wait(),那么我最终可能会在同步块内有多个线程,并且我也被迫在块末尾调用 notify() 以避免线程永远等待的情况。
- 首先,我刚才说的对吗?如果不是,那有什么问题?
- 如果是,那么应在 wait() 和 notify() 中使用 synchronized 的最常见情况是什么?
- 一般来说,如果我通过将 wait() 和 notify() 添加到同步来使代码更复杂,那么使用像 ReentrantLocks 这样更复杂的工具会更好吗?
解决方案
首先,我刚才说的对吗?如果不是,那有什么问题?
前两段恰到好处。关于等待/通知的第三段大部分是正确的。不过有几点:
- 某些线程需要调用
notify
ornotifyAll
。但它不一定是这个。 - 您可以在任何时候调用,而不仅仅是在块的末尾。无论哪种方式,在当前线程离开块之前都不会发生通知。
- 等待从未到达的通知的线程不一定永远卡住。例如,线程中断将导致
wait
以InterruptedException
.
如果是,最常见的情况
synchronized
应该与wait()
和一起使用是notify()
什么?
“应该”这个词是一个加载词。您可以使用wait()
的情况notify()
是一个线程需要等待某个事件发生的情况。(通常这用于实现条件变量。)但根据具体情况,可能有更好的方法来做到这一点。
此外,您不能使用wait()
和notify()
不持有关联的互斥锁。(如果你尝试这样做,你会得到一个例外!)
一般来说,如果我通过添加
wait()
和notify()
来使代码更复杂synchronized
,那么使用更复杂的工具会更好ReentrantLocks
吗?
一般不会。
如果有更高级别的并发类可以执行您尝试执行的操作,则通常最好使用它们而不是原始互斥锁 + 等待/通知。但情况并非总是如此。
你提到了ReentrantLock
。这个类实际上只是“在 steriods 上”的类似互斥锁。它们有一些原始互斥锁不具备的功能(例如tryLock
查看哪些线程正在等待),但是如果您不需要ReentrantLock
额外的功能,那么使用原始互斥锁并没有真正的优势。(一个可能的缺点是Lock
类不会在退出块时自动释放。所以你真的需要将它们与资源结合使用try ... finally
。try
)
推荐阅读
- python - 如何使用 pd.read_html 抓取具有 % 值的 HTML 表格?
- javascript - React 钩子表单不适用于来自 reactstrap 的输入
- python - 如何从 __init__ 访问 __init_subclass__ 中的变量?
- java - 如何在lamba表达式中抽象方法调用?
- java - 如何覆盖在 Mockito Junit 中的方法内实例化的类?
- javascript - 如何从 guacamole-common.js. 制作剪贴板流?
- amazon-web-services - AWS API Gateway Simple Lamda Authorizer 在与使用私有资源集成的 HTTP API 一起使用时失败
- c# - 有没有一种优雅的方法来分离 C# 中的插件接口和实现?
- firebird - 如何使用 FBExport 从 Firebird 数据库中导出一些数据?
- node.js - 允许 Nginx 从站点的联系表单发送电子邮件