上文讲到synchronized关键字在多线程中的使用,既然用到了锁,就会有出现死锁的状况。一个线程得到锁,若是其余线程也想得到一样的锁就会阻塞住,等待锁的释放。若是线程A已经得到锁1,还要得到锁2,同时线程B已经得到锁2,还要得到锁1,那么线程A和B就会一直阻塞住。java
依照惯例先举个例子:多线程
public class Test { public static void main(String[] args) throws InterruptedException { Object lock1 = new Object(); Object lock2 = new Object(); Thread t1 = new Thread(new Test().new Tt1(lock1, lock2)); Thread t2 = new Thread(new Test().new Tt2(lock1, lock2)); t1.start(); t2.start(); } class Tt1 implements Runnable{ private Object lock1; private Object lock2; public Tt1(Object lock1,Object lock2) { this.lock1 = lock1; this.lock2 = lock2; } @Override public void run() { synchronized (lock1) { System.out.println(this.getClass()+"-------1"); try { Thread.sleep(1000); synchronized (lock2) { System.out.println(this.getClass()+"-------2"); } } catch (InterruptedException e) { e.printStackTrace(); } } } } class Tt2 implements Runnable{ private Object lock1; private Object lock2; public Tt2(Object lock1,Object lock2) { this.lock1 = lock1; this.lock2 = lock2; } @Override public void run() { synchronized (lock2) { System.out.println(this.getClass()+"-------1"); try { Thread.sleep(1000); synchronized (lock1) { System.out.println(this.getClass()+"-------2"); } } catch (InterruptedException e) { e.printStackTrace(); } } } } }
执行结果:ide
class Test$Tt1-------1 class Test$Tt2-------1
2个线程都只执行到了第一步,就没有往下执行,都处于了阻塞状态,这就是死锁。this
死锁问题并非一个容易被发现和定位的问题,若是系统出现死锁问题,该如何定位?spa
1.使用jps,查询java虚拟机的pid
2.使用jstack打印堆栈线程
以Thread-1为例介绍下每一部分的意思
1).Thread-1 线程名称
2).prio=5 线程优先级
3).os_prio=0 本地的优先级
4).tid=0x000000001929b800 线程id
5).nid=0xfb34 本地的线程id
6)
java.lang.Thread.State: BLOCKED (on object monitor)
线程状态处于阻塞
7) waiting to lock <0x00000000d5dd0c38> (a java.lang.Object)正在等待的锁
8)locked <0x00000000d5dd0c48> (a java.lang.Object) 已获取的锁code
如今咱们能够看到Thread-1和Thread-0都处于阻塞状态,Thread-1获取了‘0x00000000d5dd0c48’锁,等待‘0x00000000d5dd0c38’锁,而Thread-0则恰好相反。图片
咱们已经知道了死锁的造成和定位,再来说讲如何避免:
1.尽可能在线程中不嵌套获取多个资源,但你只需获取一个时就不会出现死锁、
2.若是不得不嵌套使用时,要多考虑嵌套的顺序
3.死锁是由于无限的阻塞等待,若是能有一个最大的等待时间就能够解决这个问题。synchronized不具有这个功能,可是咱们可使用Lock类中的tryLock方法去尝试获取锁,这个方法能够指定一个超时时限,在等待超过该时限以后返回失败信息资源