java多线程(5)死锁

来源:互联网 发布:淘宝高仿男鞋店铺 编辑:程序博客网 时间:2024/05/21 19:33

上文讲到synchronized关键字在多线程中的使用,既然用到了锁,就会有出现死锁的情况。一个线程获得锁,如果其他线程也想获得同样的锁就会阻塞住,等待锁的释放。如果线程A已经获得锁1,还要获得锁2,同时线程B已经获得锁2,还要获得锁1,那么线程A和B就会一直阻塞住。

例子

依照惯例先举个例子:

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();                }            }        }    }}

执行结果:

class Test$Tt1-------1class Test$Tt2-------1

2个线程都只执行到了第一步,就没有往下执行,都处于了阻塞状态,这就是死锁。

定位死锁

死锁问题并不是一个容易被发现和定位的问题,如果系统出现死锁问题,该如何定位?

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) 已获取的锁

现在我们可以看到Thread-1和Thread-0都处于阻塞状态,Thread-1获取了‘0x00000000d5dd0c48’锁,等待‘0x00000000d5dd0c38’锁,而Thread-0则刚好相反。

避免死锁

我们已经知道了死锁的形成和定位,再来讲讲如何避免:
1.尽量在线程中不嵌套获取多个资源,但你只需获取一个时就不会出现死锁、
2.如果不得不嵌套使用时,要多考虑嵌套的顺序
3.死锁是因为无限的阻塞等待,如果能有一个最大的等待时间就可以解决这个问题。synchronized不具备这个功能,但是我们可以使用Lock类中的tryLock方法去尝试获取锁,这个方法可以指定一个超时时限,在等待超过该时限之后返回失败信息

原创粉丝点击