Java线程死锁是一个经典的多线程问题,因为不同的线程都在等待根本不可能被释放的锁,从而导致所有的任务都无法继续完成。在多线程技术中,“死锁”是必须要避免的,因为这会造成线程的“假死”。
下面我们来看一个具体的死锁示例:
@Test
public void testDeadLock() {
Object lockA = new Object();
Object lockB = new Object();
B14PrinterService service = new B14PrinterService(lockA, lockB);
Thread aThread = new B14PrinterAThread(service);
aThread.setName("ThreadA");
Thread bThread = new B14PrinterBThread(service);
bThread.setName("ThreadB");
aThread.start();
bThread.start();
try {
aThread.join();
bThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
class B14PrinterAThread extends Thread {
private B14PrinterService service;
public B14PrinterAThread(B14PrinterService service) {
this.service = service;
}
@Override
public void run() {
service.printA();
}
}
class B14PrinterBThread extends Thread {
private B14PrinterService service;
public B14PrinterBThread(B14PrinterService service) {
this.service = service;
}
@Override
public void run() {
service.printB();
}
}
class B14PrinterService {
private Object lockA;
private Object lockB;
public B14PrinterService(Object lockA, Object lockB) {
this.lockA = lockA;
this.lockB = lockB;
}
public void printA() {
synchronized (lockA) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("[" + Thread.currentThread().getName() + "] print A");
synchronized (lockB) {
System.out.println("[" + Thread.currentThread().getName() + "] print B");
}
}
}
public void printB() {
synchronized (lockB) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("[" + Thread.currentThread().getName() + "] print B");
synchronized (lockA) {
System.out.println("[" + Thread.currentThread().getName() + "] print A");
}
}
}
}
在上面的这个demo中,开启了ThreadA,ThreadB两个线程,其中ThreadA首先占用了lockA对象锁,并等待ThreadB释放lockB对象锁。而线程ThreadB则先占用了lockB对象锁,并等待ThreadA释放lockA对象锁,造成了ThreadA和ThreadB出现了死锁问题。
我们通过jps和jstack来证明这种推论:
通过jps命令来查看当前主机的运行的java进程,找到当前死锁的Java进程的进程号:54462。
通过 jstack 进程号 来查看当前死锁情况,可以看出 ThreadB 在等待一个lock,而这个锁正在被 ThreadA 所持有,而 ThreadA 也在等待一个lock,而这个锁也正在被 ThreadB 所持有,所以就产生了死锁的情况发生。
死锁是程序设计的BUG,在设计程序时就要避免双方互相持有对方的锁的情况。需要说明的是,本实验使用synchronized嵌套的代码结构来实现死锁,其实不使用嵌套的synchronized代码结构也会出现死锁,与嵌套不嵌套无任何关系,不要被代码结构所误导。只要互相等待对象释放锁就有可能出现死锁。
那么,通常可以用如下方式避免死锁的情况:
1、避免一个线程同时获得多个锁;
2、避免一个线程在锁内部占用多个资源,尽量保证每个锁只占用一个资源;
3、尝试使用定时锁,使用lock.tryLock(timeOut),当超时等待时当前线程不会阻塞;