我正在尝试Java多线程中的死锁概念。我遇到了一个可能导致死锁的代码片段:
public class Deadlock {
double amount = 10.0;
public double deposit(double d) {
amount += d;
return amount;
}
public double withdraw(double d) {
amount -= d;
return amount;
}
public static void transfer(Deadlock from, Deadlock to,double d) {
synchronized(from) {
synchronized(to) {
from.withdraw(d);
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(5000);
}catch(Exception e){}
to.deposit(d);
System.out.println("Done");
}
}
}
public static void main(String[] args) {
final Deadlock a = new Deadlock();
final Deadlock b = new Deadlock();
Thread t1 = new Thread(new Runnable() {
public void run() {
transfer(a, b, 10.0);
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
public void run() {
transfer(b, a, 10.0);
}
});
t2.start();
}
}
基本上,代码尝试同时获取对象a和b上的锁。但是,当我运行它时,代码总是成功完成。为什么不会出现这种僵局?
答案 0 :(得分:4)
如果一个线程能够同时到达这两个
,那么只需要线程调度程序synchronized(from) {
synchronized(to) {
在另一个线程到达第一个之前。在这些
之间添加足够大的sleep
synchronized (from) {
try {
Thread.sleep(20L);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
synchronized (to) {
你应该遇到僵局。
答案 1 :(得分:4)
为了发生死锁,你需要有之类的东西以下场景:
t1 acquires lock a
t2 acquires lock b
t1 attempts to acquire lock b
t2 attempts to acquire lock a
你能逼这个吗?您可以尝试在锁定获取之间移动睡眠语句,但这一切都必须在不受您直接控制的窗口内发生。
试试这个:
public static void transfer(DeadLock from, DeadLock to,double d) {
synchronized(from) {
try {
System.out.println(Thread.currentThread().getName() +" acquires lock " +from);
Thread.sleep(5000);
synchronized(to) {
System.out.println(Thread.currentThread().getName() +" acquires lock " +to);
from.withdraw(d);
to.deposit(d);
System.out.println("Done");
}
}catch(Exception e){}
}
}
要确认您处于死锁状态,请将SIGQUIT
信号发送到您的Java进程 - JVM将报告线程处于死锁状态
答案 2 :(得分:2)
到达方法传输的第一个线程将获得两个资源(往返),以便它可能不会与第二个线程交错。话虽如此,这段代码仍然容易陷入僵局。下面的代码尝试仅获取第一个锁,其长度足以使第二个线程计划运行:
public static void transfer(Deadlock from, Deadlock to, double d) throws InterruptedException {
synchronized (from) {
Thread.sleep(5000);
synchronized (to) {
from.withdraw(d);
System.out.println(Thread.currentThread().getName());
to.deposit(d);
System.out.println("Done");
}
}
}
答案 3 :(得分:0)
sleeping a Thread does not release the locks it holds, while waiting releases the lock
T1对两个死锁对象都有锁定,即使在休眠期间也是如此,只有当T1存在相应的同步锁时,t2才能访问它。
因此,为了引入死锁,您需要在sychronized语句之间休眠。
另外,您也可以尝试代替Thread.sleep(5000);
to.wait(5000);