Java中常見死鎖與活鎖的實例

  • 順序死鎖:過分加鎖,致使因爲執行順序的緣由,互相持有對方正在等待的鎖
  • 資源死鎖:多個線程在相同的資源上發生等待

因爲調用順序而產生的死鎖

public class Test {
    Object leftLock = new Object();
    Object rightLock = new Object();
    public static void main(String[] args) {
        final Test test = new Test();
        Thread a = new Thread(new Runnable() {
            @Override            public void run() {
               int i=0;
                while (i<10)
                {
                    test.leftRight();
                    i++;
                }
            }
        },"aThread");
        Thread b = new Thread(new Runnable() {
            @Override            public void run() {
                int i=0;
                while (i<10)
                {
                    test.rightleft();
                    i++;
                }
            }
        },"bThread");
        a.start();
        b.start();
    }

    public void leftRight(){
        synchronized (leftLock){
            System.out.println(Thread.currentThread().getName()+":leftRight:get left");
            synchronized (rightLock){
                System.out.println(Thread.currentThread().getName()+":leftRight:get right");
            }
        }
    }

    public void  rightleft(){
        synchronized (rightLock){
            System.out.println(Thread.currentThread().getName()+":rightleft: get right");
            synchronized (leftLock){
                System.out.println(Thread.currentThread().getName()+":rightleft: get left");
            }
        }
    }

}
複製代碼

運行後輸出以下java

aThread:leftRight:get left
bThread:rightleft: get right
複製代碼

能夠經過jstack發現死鎖的痕跡bash

"bThread" prio=5 tid=0x00007fabb2001000 nid=0x5503 waiting for monitor entry [0x000000011d54b000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at main.lockTest.Test.rightleft(Test.java:52)
    - waiting to lock <0x00000007aaee5748> (a java.lang.Object)
    - locked <0x00000007aaee5758> (a java.lang.Object)
    at main.lockTest.Test$2.run(Test.java:30)
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - None

"aThread" prio=5 tid=0x00007fabb2801000 nid=0x5303 waiting for monitor entry [0x000000011d448000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at main.lockTest.Test.leftRight(Test.java:43)
    - waiting to lock <0x00000007aaee5758> (a java.lang.Object)
    - locked <0x00000007aaee5748> (a java.lang.Object)
    at main.lockTest.Test$1.run(Test.java:19)
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - None
複製代碼

能夠看到bThread持有鎖0x00000007aaee5758,同時等待0x00000007aaee5748,然而剛好aThread持有鎖0x00000007aaee5748並等待0x00000007aaee5758,從而造成了死鎖app

線程飢餓死鎖

public class ExecutorLock {
    private static ExecutorService single=Executors.newSingleThreadExecutor();
    public static class AnotherCallable implements Callable<String>{

        @Override        public String call() throws Exception {
            System.out.println("in AnotherCallable");
            return "annother success";
        }
    }


    public static class MyCallable implements Callable<String>{

        @Override        public String call() throws Exception {
            System.out.println("in MyCallable");
            Future<String> submit = single.submit(new AnotherCallable());
            return "success:"+submit.get();
        }
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable task = new MyCallable();
        Future<String> submit = single.submit(task);
        System.out.println(submit.get());
        System.out.println("over");
        single.shutdown();
    }
}
複製代碼

執行的輸出只有一行ide

in MyCallable
複製代碼

經過jstack觀察能夠看到以下ui

"main" prio=5 tid=0x00007fab3f000000 nid=0x1303 waiting on condition [0x0000000107d63000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007aaeed1d8> (a java.util.concurrent.FutureTask)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:425)
    at java.util.concurrent.FutureTask.get(FutureTask.java:187)
    at main.lockTest.ExecutorLock.main(ExecutorLock.java:32)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

   Locked ownable synchronizers:
    - None
..
"pool-1-thread-1" prio=5 tid=0x00007fab3f835800 nid=0x5303 waiting on condition [0x00000001199ee000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007ab0f8698> (a java.util.concurrent.FutureTask)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:425)
    at java.util.concurrent.FutureTask.get(FutureTask.java:187)
    at main.lockTest.ExecutorLock$MyCallable.call(ExecutorLock.java:26)
    at main.lockTest.ExecutorLock$MyCallable.call(ExecutorLock.java:20)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - <0x00000007aaeed258> (a java.util.concurrent.ThreadPoolExecutor$Worker)
複製代碼

主線程在等待一個FutureTask完成,而線程池中一個線程也在等待一個FutureTask完成。
從代碼實現能夠看到,主線程往線程池中扔了一個任務A,任務A又往同一個線程池中扔了一個任務B,並等待B的完成,因爲線程池中只有一個線程,這將致使B會被停留在阻塞隊列中,而A還得等待B的完成,這也就是互相等待致使了死鎖的反生spa

這種因爲正在執行的任務線程都在等待其它工做隊列中的任務而阻塞的現象稱爲 線程飢餓死鎖線程

活鎖

並未產生線程阻塞,可是因爲某種問題的存在,致使沒法繼續執行的狀況。code

  1. 消息重試。當某個消息處理失敗的時候,一直重試,但重試因爲某種緣由,好比消息格式不對,致使解析失敗,而它又被重試隊列

    這種時候通常是將不可修復的錯誤不要重試,或者是重試次數限定資源

  2. 相互協做的線程彼此響應從而修改本身狀態,致使沒法執行下去。好比兩個頗有禮貌的人在同一條路上相遇,彼此給對方讓路,可是又在同一條路上遇到了。互相之間反覆的避讓下去

    這種時候能夠選擇一個隨機退讓,使得具有必定的隨機性

相關文章
相關標籤/搜索