美文网首页
JAVA 死锁 & 活锁

JAVA 死锁 & 活锁

作者: 王小杰at2019 | 来源:发表于2019-01-31 00:46 被阅读59次

死锁

产生死锁的四个必要条件

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

}

相关文章

  • JAVA 死锁 & 活锁

    死锁 产生死锁的四个必要条件: (1) 互斥条件:一个资源每次只能被一个进程使用。 (2) 请求与保持条件:一个进...

  • Java面试:多线程中的各种锁,你了解几个?

    学习 java 多线程时,最头疼的知识点之一就是 java 中的锁了,什么互斥锁、排它锁、自旋锁、死锁、活锁等等,...

  • 每日一技|活锁,也许你需要了解一下

    前两天看极客时间 Java 并发课程的时候,刷到一个概念:活锁。死锁,倒是不陌生,活锁却是第一次听到。 在介绍活锁...

  • 死锁

    在JAVA编程中,有3种典型的死锁类型: 静态的锁顺序死锁 动态的锁顺序死锁 协作对象之间发生的死锁 静态的锁顺序...

  • Java concurrency《防止死锁》

    Java concurrency《防止死锁》 常见预防死锁的办法 有顺序的锁 具有超时时间的锁 死锁的检测 有顺序...

  • 死锁-活锁

    死锁大家都知道,但是 有没有老铁 知道活锁呢?我在看《并发编程实战》的时候 了解到这个名次 活锁 活锁 是指 活锁...

  • 如何去检测死锁

    如何检测死锁 死锁预防 让线程获取锁的顺序一致 死锁检测 jps 查看java 进程信息 jstack +进程号 ...

  • 死锁

    线程饥饿死锁 锁顺序死锁 动态锁顺序死锁通过锁顺序来避免死锁 避免死锁

  • 高并发编程-05-活跃性问题

    死锁,饥饿,活锁 1,死锁 多个线程,各自占对方的资源,都不愿意释放,从而造成死锁 工具:使用jconsole可以...

  • 死锁与问题排查

    本篇文章从Java线程、锁层面去考虑考虑死锁。 死锁:多个线程,彼此持有对方需要的锁资源,谁也不肯释放,谁也无法进...

网友评论

      本文标题:JAVA 死锁 & 活锁

      本文链接:https://www.haomeiwen.com/subject/ytwhsqtx.html