我有这段代码。
public class UsbDrive extends HardDrive {
private Date lastUpdate;
private void updateDate() {
lastUpdate = new Date();
}
public synchronized void cutAndPaste(UsbDrive other, int originAddress, int destAddress) {
byte[] data = read(originAddress);
boolean success = other.write(data, destAddress);
if (success) {
erase(originAddress);
updateDate();
} else {
throw new RuntimeException("Write failed!");
}
}
}
class HardDrive {
...
public synchronized byte[] read(int address) {...}
public synchronized boolean write(byte[] data, int address) {...}
public synchronized void erase(int address) {...}
...
我想模拟一个僵局。
public class Main {
private static UsbDrive usb1 = new UsbDrive();
private static UsbDrive usb2 = new UsbDrive();
public static void main(String[] args) throws Exception {
Thread thread1 = new Thread(new ThreadA());
Thread thread2 = new Thread(new ThreadB());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
static class ThreadA implements Runnable {
@Override
public void run() {
try {
Thread.sleep(5000);
}
catch (Exception e) {
e.printStackTrace();
}
synchronized (usb1) {
usb1.cutAndPaste(usb2, 1, 2);
}
}
}
static class ThreadB implements Runnable {
@Override
public void run() {
synchronized (usb2) {
usb2.cutAndPaste(usb1, 1, 2);
}
}
}
}
然而死锁并没有发生--为什么?线程A调用方法 cutAndPaste()
锁定 usb1
而在该方法中 write()
被称为锁定在 usb2
不应该出现死锁吗?我应该如何修改代码来触发死锁?
我得到这样的输出。
reading data
Erasing data
reading data
Erasing data
就我所见,决定死锁是否发生的是一个竞赛条件,一个让死锁更有可能发生的好方案是循环,但一个更简单的方案可能是插入 Thread.sleep(5000);
之间 byte[] data = read(originAddress);
和 boolean success = other.write(data, destAddress);
在 UsbDrive::cutAndPaste
. EDIT: 并删除现有的 Thread.sleep(5000);
.
EDIT: 澄清的答案。
EDIT2.我刚刚运行了修改后的代码,现在确实引起了死锁:: 我刚刚运行了修改后的代码,现在确实引起了死锁。
import java.util.Date;
public class Main {
private static UsbDrive usb1 = new UsbDrive();
private static UsbDrive usb2 = new UsbDrive();
public static void main(String[] args) throws Exception {
Thread thread1 = new Thread(new ThreadA());
Thread thread2 = new Thread(new ThreadB());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
static class ThreadA implements Runnable {
@Override
public void run() {
synchronized (usb1) {
usb1.cutAndPaste(usb2, 1, 2);
}
}
}
static class ThreadB implements Runnable {
@Override
public void run() {
synchronized (usb2) {
usb2.cutAndPaste(usb1, 1, 2);
}
}
}
}
class UsbDrive extends HardDrive {
private Date lastUpdate;
private void updateDate() {
lastUpdate = new Date();
}
public synchronized void cutAndPaste(UsbDrive other, int originAddress, int destAddress) {
byte[] data = read(originAddress);
try {
Thread.sleep(5000);
}
catch (Exception e) {
e.printStackTrace();
}
boolean success = other.write(data, destAddress);
if (success) {
erase(originAddress);
updateDate();
} else {
throw new RuntimeException("Write failed!");
}
}
}
class HardDrive {
public synchronized byte[] read(int address) {return new byte[]{};}
public synchronized boolean write(byte[] data, int address) {return true;}
public synchronized void erase(int address) {}
}