Java线程死锁是一个经典的多线程问题,因为不同的线程都在等待根本不可能被释放的锁,从而导致所有的任务都无法继续完成。换言之只要互相等待对方释放锁就有可能出现死锁。下面将用一个简单的例子加以说明,如有问题,请多多指教。
某日AB两位壮士各获一张一模一样的藏宝图,他们相距甚远,互不认识。两位壮士不仅武艺双全,还富有谋略,细读藏宝图,壮士得知宝藏就在某处,但是需要两把钥匙才能开启,而这两把钥匙分别存在了某处,恰巧壮士A离钥匙1更近,壮士B离钥匙2更近,于是他们采用就近原则开启寻宝之路。A先找到了钥匙1,为了安全起见,A把钥匙收入囊中,这时B也找到了钥匙2,为了安全起见,B也把钥匙收入囊中。他们各自开始寻找第二把钥匙,但是到达他们原定的目的地之后并没有找到钥匙(其实都被对方据为己有了),但是心有不甘,心想这绝不能半途而废,他们就这样一直在苦苦等待寻找着......
上面就是多线程死锁的经典案例,两个人可看作是两个不同的线程,A获得了一把锁a想尝试获取另外一把锁b,B获取了一把锁b想尝试获取另外一把锁a,他们互相持有对方想要的锁,在没有获取到对方的锁之前,是不会将自己的锁给放弃的,这样双方永远也无法集齐两把锁,于是发生了死锁。
下面用代码来实现上面的场景:
public class DeathlyLockService { //钥匙一 private Object lock1 = new Object(); //钥匙二 private Object lock2 = new Object(); //开启宝藏之方法,线路不同,先后获取到的钥匙也不同 public void openTreasure() throws Exception{ //线路一 if(Thread.currentThread().getName().equals("大AAA")){ //先获取的是钥匙一 synchronized (lock1) { System.out.println("线程"+Thread.currentThread().getName()+"拿到了lock1"); //成功获取到一枚钥匙,继续寻找 Thread.sleep(2000); //尝试获取第二把钥匙 synchronized(lock2){ //成功获取到第二把钥匙 System.out.println("线程"+Thread.currentThread().getName()+"拿到了lock2"); Thread.sleep(2000); //开启了宝藏 System.out.println("线程"+Thread.currentThread().getName()+"集齐了两把钥匙开宝藏成功"); } } } //线路二 if(Thread.currentThread().getName().equals("小BBB")){ //先获取钥匙二 synchronized (lock2) { System.out.println("线程"+Thread.currentThread().getName()+"拿到了lock2"); //成功获取到一枚钥匙,继续寻找 Thread.sleep(2000); //尝试获取第二把钥匙 synchronized(lock1){ //成功获取到第二把钥匙 System.out.println("线程"+Thread.currentThread().getName()+"拿到了lock1"); Thread.sleep(2000); //开启了宝藏 System.out.println("线程"+Thread.currentThread().getName()+"集齐了两把钥匙开宝藏成功"); } } } } }
//自定义线程 public class MyThread extends Thread{ private DeathlyLockService deathlyLockService; public MyThread(DeathlyLockService deathlyLockService){ this.deathlyLockService=deathlyLockService; } @Override public void run(){ try { System.out.println("线程"+Thread.currentThread().getName()+"开始执行"); deathlyLockService.openTreasure(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
main方法测试:
//互相持有对方的锁,比如A对象进行操作时,需要B对象释放锁,此时B对象正在操作,需要A对象释放锁 DeathlyLockService s = new DeathlyLockService(); Thread a = new MyThread(s); a.setName("大AAA"); a.start(); Thread b = new MyThread(s); b.setName("小BBB"); b.start();
打印结果永远卡在:
线程小BBB开始执行
线程大AAA开始执行
线程小BBB拿到了lock2
线程大AAA拿到了lock1
。。。。。。
结论:因为发生了死锁,他们俩永远无法获取宝藏。知道了怎样会发生死锁,就知道如何避免这种情况的发生,希望大家以后都能开心的寻宝。