对于我的编程语言类,我们已经获得了一个简单的Java死锁示例,并被要求解决它。我不想直接得到这个问题的答案,我主要想知道我的理解缺乏的地方。这是代码:
import java.applet.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
// Attempt at a simple handshake. Girl pings Boy, gets confirmation.
// Then Boy pings girl, get confirmation.
class Monitor {
String name;
public Monitor (String name) { this.name = name; }
public String getName() { return this.name; }
// Girl thread invokes ping, asks Boy to confirm. But Boy invokes ping,
// and asks Girl to confirm. Neither Boy nor Girl can give time to their
// confirm call because they are stuck in ping. Hence the handshake
// cannot be completed.
public synchronized void ping (Monitor p) {
System.out.println(this.name + " (ping): pinging " + p.getName());
p.confirm(this);
System.out.println(this.name + " (ping): got confirmation");
}
public synchronized void confirm (Monitor p) {
System.out.println(this.name+" (confirm): confirm to "+p.getName());
}
}
class Runner extends Thread {
Monitor m1, m2;
public Runner (Monitor m1, Monitor m2) {
this.m1 = m1;
this.m2 = m2;
}
public void run () {
//System.out.println(m1.getName() + " about to ping " + m2.getName());
m1.ping(m2);
}
}
public class DeadLock {
public static void main (String args[]) {
int i=1;
System.out.println("Starting..."+(i++));
Monitor a = new Monitor("Girl");
Monitor b = new Monitor("Boy");
(new Runner(a, b)).start();
(new Runner(b, a)).start();
}
}
当我执行上面的代码时,我相信每次都会发生以下情况(虽然它没有,因为有时我们会死锁):
女孩哄男孩,锁定ping()
方法。在ping()
内,女孩试图致电boy.confirm()
。男孩的confirm()
答案,从而将我们带回Girl.ping()
完成的地方,取消了ping()
的锁定,而男孩的实例完全相同。使用所有锁定,似乎整个程序被序列化,从而破坏了多线程的目的?无论如何,我通常会得到以下输出
Starting...1
Girl (ping): pinging Boy
Boy (confirm): confirm to Girl
Girl (ping): got confirmation
Boy (ping): pinging Girl
Girl (confirm): confirm to Boy
Boy (ping): got confirmation
但有时我们会遇到死锁,输出变为:
Girl (ping): pinging Boy
Boy (ping): pinging Girl
我不明白我们如何才能进入这种状态,因为我们第一次进入时似乎已经锁定了ping()
方法,所以Boy怎么可能会调用{{1如果女孩已经在使用它了?当男孩忙着打电话ping()
时,女孩是否试图拨打boy.confirm()
?
答案 0 :(得分:5)
您的ping
方法已同步并锁定this
,然后它会继续confirm
上的p
,因此也会尝试锁定Boy
。步骤:
ping
对象上的锁定,输入Girl
; ping
对象上的锁定,输入Boy.confirm
; Girl.confirm
,等待锁定; ~
,等待锁定; 答案 1 :(得分:0)
System.out.println
进行打印
女孩(ping):pinging Boy System.out.println
以打印男孩
(ping):pinging Girl 这里的问题是public synchronized void ping (Monitor p)
表示该类的实例上的监视器。当涉及到关键部分时,两个不同的实例将完全无关。
当不同线程以不同顺序获取同步机制时,通常会发生死锁。要解决这个问题(在练习的上下文中),有两种可能性:
在类实例上进行同步,这是激进的
public void ping (Monitor p) {
synchronized(Monitor.class) {
}
}
明确同步顺序,这是详细和/或容易出错的。例如
class Runner extends Thread {
Monitor m1, m2;
bool m1_first;
public Runner (Monitor m1, Monitor m2, bool sync_m1_first) {
this.m1 = m1;
this.m1 = m2;
m1_first = sync_m1_first;
}
public void run () {
if(m1_first)
{
synchronized(m1) {
synchronized(m2) {
m1.ping(m2);
}
}
}
else
{
synchronized(m2) {
synchronized(m1) {
m1.ping(m2);
}
}
}
}
}
...
(new Runner(a, b, true)).start();
(new Runner(b, a, false)).start();