JAVA 死锁 & 活锁

死锁

产生死锁的四个必要条件

  • (1) 互斥条件:一个资源每次只能被一个进程使用。
  • (2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  • (3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
  • (4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

产生死锁, 顺序死锁



@Slf4j
public class DeadlockExample {
    static Object lockA = new Object();
    static Object lockB = new Object();


    public static void main(String[] args) {
        String name = ManagementFactory.getRuntimeMXBean().getName();
        String pid = name.split("@")[0];
        log.info("Pid is:" + pid);
        log.info("jstack " + pid);

        ExecutorService executorService = Executors.newCachedThreadPool();

        executorService.submit(() -> {
            synchronized (lockA) {
                try {
                    log.info("lockA");
                    TimeUnit.SECONDS.sleep(10);
                    log.info("lockA after sleep");

                    synchronized (lockB) {
                        log.info("lock B");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        });

        executorService.submit(() -> {
            synchronized (lockB) {
                try {
                    log.info("lockB");
                    TimeUnit.SECONDS.sleep(10);
                    log.info("lockB after sleep");

                    synchronized (lockA) {
                        log.info("lock A");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

    }

}

分析信息 Found one Java-level deadlock:

Found one Java-level deadlock:
=============================
"pool-1-thread-1":
  waiting to lock monitor 0x000002c99012fa80 (object 0x0000000710944898, a java.lang.Object),
  which is held by "pool-1-thread-2"
"pool-1-thread-2":
  waiting to lock monitor 0x000002c99012bb80 (object 0x0000000710944888, a java.lang.Object),
  which is held by "pool-1-thread-1"

Java stack information for the threads listed above:
===================================================
"pool-1-thread-1":
        at cn.wyj.learn.juc.DeadlockExample.lambda$main$0(DeadlockExample.java:33)
        - waiting to lock <0x0000000710944898> (a java.lang.Object)
        - locked <0x0000000710944888> (a java.lang.Object)
        at cn.wyj.learn.juc.DeadlockExample$$Lambda$41/0x00000008000e2440.run(Unknown Source)
        at java.util.concurrent.Executors$RunnableAdapter.call(java.base@11.0.2/Executors.java:515)
        at java.util.concurrent.FutureTask.run(java.base@11.0.2/FutureTask.java:264)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.2/ThreadPoolExecutor.java:1128)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.2/ThreadPoolExecutor.java:628)
        at java.lang.Thread.run(java.base@11.0.2/Thread.java:834)
"pool-1-thread-2":
        at cn.wyj.learn.juc.DeadlockExample.lambda$main$1(DeadlockExample.java:50)
        - waiting to lock <0x0000000710944888> (a java.lang.Object)
        - locked <0x0000000710944898> (a java.lang.Object)
        at cn.wyj.learn.juc.DeadlockExample$$Lambda$42/0x00000008000e1840.run(Unknown Source)
        at java.util.concurrent.Executors$RunnableAdapter.call(java.base@11.0.2/Executors.java:515)
        at java.util.concurrent.FutureTask.run(java.base@11.0.2/FutureTask.java:264)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.2/ThreadPoolExecutor.java:1128)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.2/ThreadPoolExecutor.java:628)
        at java.lang.Thread.run(java.base@11.0.2/Thread.java:834)

Found 1 deadlock.

活锁

指事物1可以使用资源,但它让其他事物先使用资源;事物2可以使用资源,但它也让其他事物先使用资源,于是两者一直谦让,都无法使用资源。

活锁同样会发生在多个相互协作的线程间,当他们为了彼此间的响应而相互礼让,使得没有一个线程能够继续前进,那么就发生了活锁。

好比两个过于礼貌的人在半路相遇,出于礼貌他们相互礼让,避开对方的路,但是在另一条路上又相遇了。就这样,不停地一直避让下去。。。。



@Slf4j
public class DeadlockExample {

    static ReentrantLock reentrantLockA = new ReentrantLock();
    static ReentrantLock reentrantLockB = new ReentrantLock();

    public static void main(String[] args) {
        String name = ManagementFactory.getRuntimeMXBean().getName();
        String pid = name.split("@")[0];
        log.info("Pid is:" + pid);
        log.info("jstack " + pid);

        ExecutorService executorService = Executors.newCachedThreadPool();

        executorService.submit(() -> {
            try {
                while (reentrantLockA.tryLock(10, TimeUnit.SECONDS)) {
                    log.info("A任务重新初始化");
                    TimeUnit.SECONDS.sleep(1);
                    boolean locked = reentrantLockB.isLocked();
                    if (locked) {
                        reentrantLockA.unlock();
                        continue;
                    }
                    boolean b = reentrantLockB.tryLock(10, TimeUnit.SECONDS);
                    if (!b) {
                        reentrantLockA.unlock();
                        continue;
                    }
                    log.info("线程A处理任务");
                    break;
                }
                log.info("线程A处理完成");
            } catch (InterruptedException e) {
                log.error("线程中断", e);
            } finally {
                reentrantLockB.unlock();
                reentrantLockA.unlock();
            }
        });

        executorService.submit(() -> {
            try {
                while (reentrantLockB.tryLock(10, TimeUnit.SECONDS)) {
                    log.info("B任务重新初始化");
                    TimeUnit.SECONDS.sleep(2);
                    boolean locked = reentrantLockA.isLocked();
                    if (locked) {
                        reentrantLockB.unlock();
                        continue;
                    }
                    boolean b = reentrantLockA.tryLock(10, TimeUnit.SECONDS);
                    if (!b) {
                        reentrantLockB.unlock();
                        continue;
                    }
                    log.info("线程B处理任务");
                    break;
                }
                log.info("线程B处理完成");
            } catch (InterruptedException e) {
                log.error("线程中断", e);
            } finally {
                reentrantLockA.unlock();
                reentrantLockB.unlock();
            }
        });
        executorService.shutdown();
    }

}
    
10:55:25.434 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
10:55:25.434 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
10:55:26.435 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
10:55:27.436 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
10:55:29.436 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
10:55:31.437 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
10:55:33.438 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
.
.
.
.
.
.

10:57:41.497 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
10:57:42.493 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
10:57:43.493 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
10:57:43.498 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
10:57:44.493 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
10:57:45.493 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
10:57:45.498 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
10:57:46.494 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化

解决活锁1

在锁让出的时候时候添加随机睡眠时间,

@Slf4j
public class DeadlockExample {

    static ReentrantLock reentrantLockA = new ReentrantLock();
    static ReentrantLock reentrantLockB = new ReentrantLock();

    public static void main(String[] args) {
        String name = ManagementFactory.getRuntimeMXBean().getName();
        String pid = name.split("@")[0];
        log.info("Pid is:" + pid);
        log.info("jstack " + pid);

        ExecutorService executorService = Executors.newCachedThreadPool();

        executorService.submit(() -> {
            try {
                //自旋
                while (reentrantLockA.tryLock(10, TimeUnit.SECONDS)) {
                    log.info("A任务重新初始化");
                    TimeUnit.SECONDS.sleep(1);
                    boolean locked = reentrantLockB.isLocked();
                    if (locked) {
                        reentrantLockA.unlock();
                        //避免活锁
                        TimeUnit.MILLISECONDS.sleep(RandomUtils.nextInt(1,2000));
                        continue;
                    }
                    boolean b = reentrantLockB.tryLock(10, TimeUnit.SECONDS);
                    if (!b) {
                        reentrantLockA.unlock();
                        continue;
                    }
                    log.info("线程A处理任务");
                    break;
                }
                log.info("线程A处理完成");
            } catch (InterruptedException e) {
                log.error("线程中断", e);
            } finally {
                reentrantLockB.unlock();
                reentrantLockA.unlock();
            }
        });

        executorService.submit(() -> {
            try {
                //自旋
                while (reentrantLockB.tryLock(10, TimeUnit.SECONDS)) {
                    log.info("B任务重新初始化");
                    TimeUnit.SECONDS.sleep(2);
                    boolean locked = reentrantLockA.isLocked();
                    if (locked) {
                        reentrantLockB.unlock();
                        //避免活锁
                        TimeUnit.MILLISECONDS.sleep(RandomUtils.nextInt(1, 2000));
                        continue;
                    }
                    boolean b = reentrantLockA.tryLock(10, TimeUnit.SECONDS);
                    if (!b) {
                        reentrantLockB.unlock();
                        continue;
                    }
                    log.info("线程B处理任务");
                    break;
                }
                log.info("线程B处理完成");
            } catch (InterruptedException e) {
                log.error("线程中断", e);
            } finally {
                reentrantLockA.unlock();
                reentrantLockB.unlock();
            }
        });
        executorService.shutdown();
    }

}


11:28:22.212 [main] INFO cn.wyj.learn.juc.DeadlockExample - Pid is:33004
11:28:22.215 [main] INFO cn.wyj.learn.juc.DeadlockExample - jstack 33004
11:28:22.219 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
11:28:22.219 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
11:28:23.845 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - A任务重新初始化
11:28:24.846 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - 线程A处理任务
11:28:24.846 [pool-1-thread-1] INFO cn.wyj.learn.juc.DeadlockExample - 线程A处理完成
11:28:25.546 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - B任务重新初始化
11:28:27.547 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - 线程B处理任务
11:28:27.547 [pool-1-thread-2] INFO cn.wyj.learn.juc.DeadlockExample - 线程B处理完成

解决活锁2 约定优先级

线程A 是等待10S 才让出所, 线程B如果发现已经被锁定那么立即释放锁


@Slf4j
public class DeadlockExample3 {

    static ReentrantLock reentrantLockA = new ReentrantLock();
    static ReentrantLock reentrantLockB = new ReentrantLock();

    public static void main(String[] args) {
        String name = ManagementFactory.getRuntimeMXBean().getName();
        String pid = name.split("@")[0];
        log.info("Pid is:" + pid);
        log.info("jstack " + pid);

        ExecutorService executorService = Executors.newCachedThreadPool();

        executorService.submit(() -> {
            try {
                //自旋
                while (reentrantLockA.tryLock(10, TimeUnit.SECONDS)) {
                    log.info("A任务重新初始化");
                    TimeUnit.SECONDS.sleep(1);
                    boolean b = reentrantLockB.tryLock(10, TimeUnit.SECONDS);
                    if (!b) {
                        reentrantLockA.unlock();
                        continue;
                    }
                    log.info("线程A处理任务");
                    break;
                }
                log.info("线程A处理完成");
            } catch (InterruptedException e) {
                log.error("线程中断", e);
            } finally {
                reentrantLockB.unlock();
                reentrantLockA.unlock();
            }
        });

        executorService.submit(() -> {
            try {
                //自旋
                while (reentrantLockB.tryLock(10, TimeUnit.SECONDS)) {
                    log.info("B任务重新初始化");
                    TimeUnit.SECONDS.sleep(2);
                    boolean locked = reentrantLockA.isLocked();
                    if (locked) {
                        reentrantLockB.unlock();
                        //避免活锁
                        TimeUnit.MILLISECONDS.sleep(RandomUtils.nextInt(1, 2000));
                        continue;
                    }
                    boolean b = reentrantLockA.tryLock(10, TimeUnit.SECONDS);
                    if (!b) {
                        reentrantLockB.unlock();
                        continue;
                    }
                    log.info("线程B处理任务");
                    break;
                }
                log.info("线程B处理完成");
            } catch (InterruptedException e) {
                log.error("线程中断", e);
            } finally {
                reentrantLockA.unlock();
                reentrantLockB.unlock();
            }
        });
        executorService.shutdown();
    }

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 原文链接:死锁和活锁,饿死,阻塞个人理解 死锁 线程A或者B需要过独木桥(使用该进程),而C还没有走完(进程还在占...
    Jokerone_阅读 5,891评论 0 8
  • 死锁 deadlock 死锁指两个或两个以上进程(或线程)持有或者循环持有彼此资源,导致相互等待现象,如无外力介入...
    网虫子阅读 693评论 0 0
  • 1、竞态条件: 定义:竞态条件指的是一种特殊的情况,在这种情况下各个执行单元以一种没有逻辑的顺序执行动作,从而导致...
    Hughman阅读 1,416评论 0 7
  • 在一个方法内部定义的变量都存储在栈中,当这个函数运行结束后,其对应的栈就会被回收,此时,在其方法体中定义的变量将不...
    Y了个J阅读 4,540评论 1 14
  • 所以我今天准备分四部分给大家分享。 第一部分,我会讲区块链, 第二部分讲比特币, 第三部分讲ICO, 最后总结一下...
    Platero_6cf6阅读 627评论 0 0

友情链接更多精彩内容