java - 扎实的 Java 开发人员中的 Java 死锁示例
问题描述
没看懂《扎扎实实的java开发者》一书中的死锁例子。怎么会出现这种僵局?
乍一看,这段代码看起来很合理。您有两个更新被发送到不同的线程,每个更新都必须在备份线程上得到确认。这似乎不是一个太古怪的设计——如果一个线程出现故障,那么另一个线程可能会继续运行。如果你运行代码,你通常会看到一个死锁的例子——两个线程都将报告接收到更新,但都不会确认接收到它们作为备份线程的更新。这样做的原因是每个线程都需要另一个线程在确认方法可以进行之前释放它持有的锁。
下面是来自代码清单 4.2 的一个死锁示例
public class MicroBlogNode implements SimpleMicroBlogNode {
private final String ident;
public MicroBlogNode(String ident_) {
ident = ident_;
}
public String getIdent() {
return ident;
}
public synchronized void propagateUpdate(Update upd_, MicroBlogNode
backup_) {
System.out.println(ident + ": recvd: " + upd_.getUpdateText() + " ; backup: " + backup_.getIdent());
backup_.confirmUpdate(this, upd_);
}
public synchronized void confirmUpdate(MicroBlogNode other_, Update
update_) {
System.out.println(ident + ": recvd confirm: " + update_.getUpdateText() + " from " + other_.getIdent()k);
}
public static void main(String[] args) {
final MicroBlogNode local = new MicroBlogNode("localhost:8888");
final MicroBlogNode other = new MicroBlogNode("localhost:8988");
final Update first = getUpdate("1");
final Update second = getUpdate("2");
new Thread(new Runnable() {
public void run() {
local.propagateUpdate(first, other);
}
}).start();
new Thread(new Runnable() {
public void run() {
other.propagateUpdate(second, local);
}
}).start();
}
解决方案
第一个线程启动,local.propagateUpdate
被调用,local
现在被锁定,因为方法是同步的。
几乎同时,第二个线程被启动,other.propagateUpdate
被调用并且实例other
也因为同样的原因被锁定。
两个线程都愉快地打印文本。在第一个线程中,local
实例尝试通过调用实例与另一个线程确认confirmUpdate
,other
但other
仍被第二个线程锁定 - 该方法尚未返回。
在第二个线程中,other
实例尝试调用confirmUpdate
该local
实例,但该实例也被锁定 - 这次是由第一个线程锁定的。
local
并且other
都在等待对方释放他们的锁,并且永远无法解决问题:这是死锁。
推荐阅读
- mongoose - 使用 Mongoose 的媒体提要
- javascript - 渲染之间的 React 缓存组件
- java - 使用 json 的 Spring 引导文件上传中不存在必需的 FileUpload[] 参数“body”
- android - 对话框中的列表视图项目未对齐
- sqlite - 自定义前缀后的额外空格 [Discord.py]
- karate - 空手道框架是否支持无头浏览器测试?
- r - 无法在 R 3.5.2 上安装 Seurat 或 devtools
- regex - 应该从 URL 中省略哪些字符以使其不被编码?(即更具人类可读性)
- ios - XCODE:UIView 背景没有出现在屏幕上,即使我在情节提要中设置了颜色并以编程方式
- java - 为什么我的工作没有显示我的转移工作