Java中的线程死锁

线程死锁概念

两个或两个以上的线程在执行过程中同时被阻塞,它们中的某个或者全部都在等待某个资源被释放,由于线程被无限期的阻塞,系统处于死锁状态或系统产生了死锁,这些永远在互相等待的线程被称为线程死锁。

线程/资源 资源1 资源2
线程1 占有 等待
线程2 等待 占有
示例代码:
public static void main(String[] args) {
    Object wzLock = new Object();
    Object cjLock = new Object();
    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (wzLock) {
                System.out.println(Thread.currentThread().getName() + "---> 先玩王者");
                synchronized (cjLock) {
                    System.out.println(Thread.currentThread().getName() + "---> 后玩吃鸡");
                }
            }
        }
    },"王者爱好者");
    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (cjLock) {
                System.out.println(Thread.currentThread().getName() + "---> 先玩吃鸡");
                synchronized (wzLock) {
                    System.out.println(Thread.currentThread().getName() + "---> 后玩王者");
                }
            }
        }
    },"吃鸡爱好者");
    t1.start();
    t2.start();
}

执行结果:

线程t1先获取并占有资源wzLock,
线程t2先获取并占有资源cjLock,
由于t1无法再获取cjLock,t2也无法再获取wzLock,从而导致线程一直等待,形成死锁。

启用JDK自带的jconsole查看线程情况

WIN + R --> cmd --> jconsole --> enter

如何避免死锁

死锁产生的四个必要条件:

  1. 互斥使用:当一个资源被另一个线程使用(占有)时,别的线程不能使用。
  2. 不可抢占:资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
  3. 请求和保持:当资源请求者在请求其他的资源的同时保持对原有资源的占有。
  4. 循环等待:在一个等待队列:P1占有P2的资源,P2占有P3的资源…Pn占有P1的资源,这样就形成了一个等待环路。

当上述四个条件全部成立时,就形成死锁,要想解除死锁只需要破坏上述任何一个条件即可。

代码改造:
public static void main(String[] args) {
    Object wzLock = new Object();
    Object cjLock = new Object();
    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (wzLock) {
                System.out.println(Thread.currentThread().getName() + "---> 先玩王者");
                synchronized (cjLock) {
                    System.out.println(Thread.currentThread().getName() + "---> 后玩吃鸡");
                }
            }
        }
    },"王者爱好者");
    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (wzLock) {
                System.out.println(Thread.currentThread().getName() + "---> 先玩吃鸡");
                synchronized (cjLock) {
                    System.out.println(Thread.currentThread().getName() + "---> 后玩王者");
                }
            }
        }
    },"吃鸡爱好者");
    t1.start();
    t2.start();
}

posted @ 2023-06-09 10:30  #码农9527#  阅读(19)  评论(0)    收藏  举报