本文介绍死锁产生的条件及优化方案。
死锁产生
- 线程互相等待 - 常见的死锁有JDK死锁和数据库死锁。 - 以JDK死锁为例: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40- public class Deadlock { 
 static class Friend {
 private final String name;
 public Friend(String name) {
 this.name = name;
 }
 public String getName() {
 return this.name;
 }
 
 //同步锁bow
 public synchronized void bow(Friend bower) {
 System.out.format("%s: %s"
 + " has bowed to me!%n",
 this.name, bower.getName());
 //调用同步锁bowBack
 bower.bowBack(this);
 }
 
 //同步锁bowBack
 public synchronized void bowBack(Friend bower) {
 System.out.format("%s: %s"
 + " has bowed back to me!%n",
 this.name, bower.getName());
 }
 }
 public static void main(String[] args) {
 final Friend alphonse =
 new Friend("Alphonse");
 final Friend gaston =
 new Friend("Gaston");
 new Thread(new Runnable() {
 public void run() { alphonse.bow(gaston); }
 }).start();
 new Thread(new Runnable() {
 public void run() { gaston.bow(alphonse); }
 }).start();
 }
 }- 输出: - 1 
 2- Alphonse: Gaston has bowed to me! 
 Gaston: Alphonse has bowed to me!- 分析: - 执行程序期望是alphonse向gaston鞠躬,并等待gaston还礼;gaston向alphonse鞠躬,并等待alphonse还礼。 - 两个线程,分别是alphonse线程和gaston线程; - alphonse线程传入gaston对象,gaston传入alphonse对象,均执行执行bowBack。- 问题是: 
 如果单线程执行,例如alphonse线程执行,结果会是:- 1 
 2- Alphonse: Gaston has bowed to me! 
 Gaston: Alphonse has bowed back to me!- 多线程执行时,alphonse和gaston互相鞠躬,但是均等待对方回礼,则在bowBack产生等待死锁。 - alphonse和gaston均为对象锁,但是内部进行了互相调用 - bowBack(Friend bower)。
- alphonse获得对象锁,gaston获得对象锁。 
- alphonse同步调用bow,gaston同步调用bow;没有问题,不会死锁。 
- alphonse同步锁继续,使用gaston对象调用bowBack,但是gaston也在使用alphonse对象调用bowBack,产生问题。 
- alphonse->gaston->bowBack;gaston->alphonse->bowBack;因此alphonse和gaston对象锁都互相加锁且等待对方释放锁,导致死锁。 
 
- 死锁查看 - 查看进程执行情况: - 1 - jstack -l 69733 
   或者采用VisualVM,查看两个对象锁处于等待状态
   
- 除了死锁还有活锁、饥饿锁 
避免死锁方法
- 避免一个线程操作获取多个锁,例如上例中一个方法内获取两个对象锁 
- 避免一个线程在锁内占用多个资源,尽量保证每个锁占用一个,例如上例一个方法期望锁定两个对象 
- 采用定时锁,即lock.tryLock(timeout),即在限定时间内获取锁,获取不到则放弃,防止死锁等待 - 1 
 2
 3
 4
 5
 6
 7
 8
 9- /** 
 * @return {@code true} 如果当前线程请求到锁或者本来就拥有锁
 * @throws InterruptedException if the current thread is interrupted
 * @throws NullPointerException if the time unit is null
 */
 public boolean tryLock(long timeout, TimeUnit unit)
 throws InterruptedException {
 return sync.tryAcquireNanos(1, unit.toNanos(timeout));
 }
- 对于数据库锁,加锁和解锁在一个数据库连接,否则解锁失败。同一个对象锁进行加锁和解锁操作。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9- try { 
 //关闭事务自动提交(开启事务)
 this.connection.setAutoCommit(false);
 //无异常,手动提交
 this.connection.commit();
 } catch(Exception e) {
 //当前;连接回滚
 this.connection.rollback();
 }
并发包JUC使用
参考Orace文档