请问,请知道以下程序是否可以保证死锁?以下是详细信息: 线程:process1和process2。 对象:扫描仪和打印机。 process1锁定扫描仪和打印机,但放弃扫描仪。 process2锁定扫描程序但无法获取打印机,因为process1已将其锁定。也许我的线程概念不清楚,但请问,我可以知道我哪里出错了吗?
class DeadLock extends Thread {
//creating a scanner object
private static Object scanner = new Object();
//creating a printer object
private static Object printer = new Object();
//the process name
private String processName;
//initializes process2 is not created yet
private boolean process2IsCreated = false;
/**
* the constructor which sets string to process1 or 2
* @param string
*/
public DeadLock(String string) {
// TODO Auto-generated constructor stub
this.processName = string;
}
/**
* deadlock() for process1
*/
public void deadlock1() {
//process1 locks scanner
synchronized (scanner) {
//process1 locks printer, too
synchronized (printer) {
//create process2 after process1
if(process2IsCreated == false && processName.equals("process1")) {
new DeadLock("process2").start();
process2IsCreated = true;
}
try {
//process1 is waiting on scanner and releases its monitor.
//After regaining access, process1 tries to acquire scanner
//but cannot do so because process2 has locked it already.
//. . .too late, process1!
scanner.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* deadlock() for process2
*/
public void deadlock2() {
//process2 locks scanner
synchronized (scanner) {
//process2 notifies process1 which is waiting on scanner
scanner.notify();
//process2 locks printer, but cannot lock printer because process1 has it
//. . .too late, process2!
synchronized (printer) {
}
}
}
/**
* both threads are scheduled to execute run()
*/
public void run() {
//if process1 then enter deadlock1()
if(processName.equals ("process1")) deadlock1();
//if process 2 then enter deadlock2()
else deadlock2();
}
/**
* the main method which creates thread process1
* @param a
*/
public static void main(String a[]) {
new DeadLock("process1").start();
}
}
答案 0 :(得分:2)
这似乎对我有用,这里是Intellij中的Thread Dump:
答案 1 :(得分:0)
看到这个..这里第二个线程正在启动
//create process2 after process1
if(process2IsCreated == false && processName.equals("process1")) {
new DeadLock("process2").start(); <---------------HERE
process2IsCreated = true;
}
答案 2 :(得分:0)
I guess, the flow is..
Thread 1 : takes scanner lock
Thread 1: takes printer lock
Thread 1: creates and starts 2nd thread
Possible flow:
Thread 2 : Starts, executes run and goes into deadlock2()
Thread 1: waits for object scanner
Thread 2: Enters lock Scanner
Thread 2: Notifies lock scanner
Thread 2: stuck as it cant get into printer block as Thread 1 has it
Thread 1: Is waiting for Thread 2 to leave scanner block which it does not.
Result: Thread 2 can not have Printer & Thread 1 can not start executing as Thread 2 even when it is notified scanner , has not left Scanner block.
This is not a proper deadlock as thread 1 has not returned for execution.
答案 3 :(得分:0)
自从我使用Java的同步原语以来已经有一段时间了,但对我来说它看起来像:
线程1锁定扫描仪
线程1锁定打印机
线程2启动
线程1暂时释放扫描仪,等待通知等待
线程2锁定扫描仪。
线程2发布通知。
线程2在打印机上阻止。
线程1永远不会唤醒,因为线程2永远不会释放扫描仪 线程2永远不会被唤醒,因为线程1还没有完成打印机。
我的猜测是你首先让线程1睡眠错误。它已经获得了两种资源,还有什么等待的呢?
你也有可能过度使用同步;通常,简单synchronized
块(监视器)或wait
/ notify
调用(信号量)可能就足够了。你正在使用它们。
我认为这里的经验法则是,“如果您打算使用wait
/ notify
,请将它们包装在最小synchronized
块中”。线程2中的扫描程序块延伸超过notify
调用,进入打印机块。
-
澄清:
synchronized (x) { A; }
synchronized (x) { B; }
是(使用)监视器,用于当您不希望A和B同时执行时。
synchronized (x) { x.wait(); } B;
A; synchronized (x) { x.notify(); }
使用信号量确保A在B之前执行。
答案 4 :(得分:0)
是的,这是一个几乎完美的死锁示例,原因如下(Oracle wait()doc):
线程发布 此监视器的所有权,并等待另一个线程通知 在此对象的监视器上等待的线程唤醒[...]
因此显示器扫描仪已释放,但显示器打印机未释放。这就是你不应该两次同步的原因。
您的代码只有一个问题,即spurious wakeups。它可能发生(虽然它不太可能),等待呼叫突然醒来,没有人曾经通知过。这更多是操作系统中锁定实现的原因,而不是与Java有关,但是在正确的操作系统上运行,您的死锁最终可能会在几天,几个月或几年后醒来。