在多线程中,为了保证数据等准确性和一致性,一般在进行共享数据进行操作等时候,我们都会进行加锁,保证同一时间只有一个线程在操作这个对象。由于加锁的原因,如果一不注意的话很容易导致死锁。死锁的原因是两个线程或者多个线程在互相等待对方释放资源,一直在阻塞等待,这就造成了死锁。由于Java中没有对死锁进行监管的东西,在死锁中,线程会一直被阻塞,程序不会有任何提示的消息,也无法继续下去。
下面是一个死锁的例子,可以帮助大家理解死锁的机制:
package lock;
/**
* Created by pozhen on 17/2/12.
* 1.首先开启一个线程(副线程),启动线程后,会先进入run方法,run方法执行b.hold(a)方法,给b对象加了锁,然后休眠200ms
* 2.然后主线程几乎是和副线程同时,但是会慢上一些进入init()方法,然后执行a.hold(b)方法,给a对象加了锁,然后休眠200ms
* 3.b对象会提前结束休眠,将要执行代码4,需要给a对象加锁,但是现在a对象的锁被副线程持有,所以主线程阻塞,等待副线程释放a对象的锁。
* 4.这时候副线程的休眠也结束了,将要执行代码2,需要给b加锁,但是现在b对象的锁被主线程持有,所以副线程阻塞,等待主线程释放b对象的锁。
* 5.最后,主线程阻塞在等副线程释放锁,副线程也在阻塞等待主线程释放锁,这时候就一直等待下去,无穷无尽,这就造成了死锁。
*/
public class DeadLockExample implements Runnable{
class A {
public synchronized void hold(B b) {
try {
System.out.println(Thread.currentThread().getName()+"目前持有A的锁");//代码1
Thread.sleep(200);
}catch (Exception e) {
e.printStackTrace();
}
b.last();
}
public synchronized void last() {
System.out.println(Thread.currentThread().getName()+"的A对象企图访问B对象的last方法,准备要给B对象加锁");//代码2
}
}
class B {
public synchronized void hold(A a) {
try {
System.out.println(Thread.currentThread().getName()+"目前持有B的锁");//代码3
Thread.sleep(200);
}catch (Exception e) {
e.printStackTrace();
}
a.last();
}
public synchronized void last() {
System.out.println(Thread.currentThread().getName()+"的B对象企图访问A对象的last方法,准备要给A对象加锁");//代码4
}
}
A a = new A();
B b = new B();
public void init() {
Thread.currentThread().setName("主线程");
a.hold(b);
}
@Override
public void run() {
Thread.currentThread().setName("副线程");
b.hold(a);
}
public static void main(String[] args) {
DeadLockExample deadLockExample = new DeadLockExample();
new Thread(deadLockExample).start();
deadLockExample.init();
}
}