1、线程死锁产生的原因:
-
不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,这样就会造成线程的死锁问题
- 出现线程死锁之后,程序不会报异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续执行
- 死锁产生的四个必要条件
- 互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
- 不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
- 请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
- 循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。
- 当上述四个条件都成立的时候,便形成死锁。当然,死锁的情况下如果打破上述任何一个条件,便可让死锁消失。
2、线程死锁的代码实例:
1 package com.baozi.thread; 2 3 /** 4 * 用两个线程请求被对方占用的资源,实现线程死锁 5 * 6 * 7 */ 8 public class DeadLockThread implements Runnable { 9 private static final Object objectA = new Object(); 10 private static final Object objectB = new Object(); 11 private boolean flag; 12 13 @Override 14 public void run() { 15 String threadName = Thread.currentThread().getName(); 16 System.out.println("当前线程 为:" + threadName + " flag = " + flag); 17 if (flag) { 18 synchronized (objectA) { 19 try { 20 Thread.sleep(1000); 21 } catch (InterruptedException e) { 22 // TODO Auto-generated catch block 23 e.printStackTrace(); 24 } 25 System.out.println(threadName + "已进入同步代码块objectA,准备进入objectB"); 26 synchronized (objectB) { 27 System.out.println(threadName + "已经进入同步代码块objectB"); 28 } 29 } 30 31 } else { 32 synchronized (objectB) { 33 try { 34 Thread.sleep(1000); 35 } catch (InterruptedException e) { 36 // TODO Auto-generated catch block 37 e.printStackTrace(); 38 } 39 System.out.println(threadName + "已进入同步代码块objectB,准备进入objectA"); 40 synchronized (objectA) { 41 System.out.println(threadName + "已经进入同步代码块objectA"); 42 } 43 } 44 } 45 } 46 47 public static void main(String[] args) { 48 DeadLockThread deadlock1 = new DeadLockThread(); 49 DeadLockThread deadlock2 = new DeadLockThread(); 50 deadlock1.flag = true; 51 deadlock2.flag = false; 52 Thread thread1 = new Thread(deadlock1); 53 Thread thread2 = new Thread(deadlock2); 54 thread1.start(); 55 thread2.start(); 56 57 } 58 59 }
3、解决方法
要预防和避免死锁的发生,只需将上面所讲到的4个条件破坏掉其中之一即可。
如上面的代码当中,由于有四个同步代码块,代表着线程要占用的资源,只需要将其中一个同步代码块去掉,即可解决死锁问题。
一般而言破坏“循环等待”这个条件是解决死锁最有效的方法
4、预防线程死锁应该遵循的原则:
- 尽量的减少同步资源的定义
- 尽量避免嵌套同步
- 采用专门的算法、原则