虽然网上有各种关于死锁的说法,但是却没有一个实际的案例来阐述这个死锁到底是什么样的
那么这里有一个简单的死锁实例:
线程t1需要先使用扫描仪扫描文件、再使用打印机打印文件,之后工作完毕
线程t2需要先使用打印机打印文件、再使用扫描仪扫描文件,之后工作完毕
如果是正常的工作秩序,那应该是t1先拥有扫描仪的使用权,而t2呢则拥有打印机的使用权,此时则大家秩序井然的工作直至工作完毕
但死锁往往是发生在一些意外的情况,如t1要先扫描文件但却拥有了打印机的使用权限,而没有扫描仪的使用权限,t2则相反,此时大家都在等待对方使用完成后,让出使用权限,这样无限制的等待下去,就造成了我们所谓的“死锁”
PS:这里不同的调度方式,结果也会不同。例如使用权都是t1,或都是t2等
代码如下:
public class Test implements Runnable {
Scanner scanner;
Printer printer;
int scannerTurn = 2, printerTurn = 1;
boolean isScannerT1Done = false, isScannerT2Done = false;
boolean isPrinterT1Done = false, isPrinterT2Done = false;
Test(Scanner s, Printer p) {
scanner = s;
printer = p;
}
public static void main(String[] args) {
new Test(new Scanner(), new Printer()).run();
}
@Override
public void run() {
new Thread("t1") {
@Override
public void run() {
// TODO Auto-generated method stub
//扫描和打印都完成,工作结束
while(!(isScannerT1Done && isPrinterT1Done)) {
synchronized (scanner) {
if(scannerTurn == 1) {
if(!isScannerT1Done) {
scanner.work(getName());
scannerTurn = 2;
isScannerT1Done = true;
}
}
else
try {
System.out.println(getName() + " is waiting for printer...");
//没有使用权限,等待通知
scanner.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//通知等待使用扫描仪的线程,现在打印机可以使用了
scanner.notifyAll();
}
synchronized (printer) {
if(printerTurn == 1 && !isPrinterT1Done) {
printer.work(getName());
System.out.println(getName() + " is done!");
printerTurn = 2;
isPrinterT1Done = true;
}
//通知等待使用打印机的线程,现在打印机可以使用了
printer.notifyAll();
}
}
}
}.start();
new Thread("t2") {
@Override
public void run() {
// TODO Auto-generated method stub
//打印和扫描都完成,工作结束
while(!(isScannerT2Done && isPrinterT2Done)) {
synchronized (printer) {
if(printerTurn == 2) {
if(!isPrinterT2Done) {
printer.work(getName());
printerTurn = 1;
isPrinterT2Done = true;
}
}
else
try {
System.out.println(getName() + " is waiting for scanner...");
//没有使用权限,等待通知
printer.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//通知等待使用打印机的线程,现在打印机可以使用了
printer.notifyAll();
}
synchronized (scanner) {
if(scannerTurn == 2 && !isScannerT2Done) {
scanner.work(getName());
System.out.println(getName() + " is done!");
isScannerT2Done = true;
scannerTurn = 1;
}
//通知等待使用扫描仪的线程,现在打印机可以使用了
scanner.notifyAll();
}
}
}
}.start();
}
static class Scanner {
void work(String s) {
System.out.println(s + " scan successful!");
}
}
static class Printer {
void work(String s) {
System.out.println(s + " print successful!");
}
}
}