本文介紹了java中常見死鎖與活鎖的實例詳解,分享給大家,具體如下:
- 順序死鎖:過度加鎖,導致由于執行順序的原因,互相持有對方正在等待的鎖
- 資源死鎖:多個線程在相同的資源上發生等待
由于調用順序而產生的死鎖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
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" ); } } } } |
運行后輸出如下
athread:leftright:get left
bthread:rightleft: get right
可以通過jstack發現死鎖的痕跡
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
"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,從而形成了死鎖
線程饑餓死鎖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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(); } } |
執行的輸出只有一行
1
|
in mycallable |
通過jstack觀察可以看到如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
"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的完成,這也就是互相等待導致了死鎖的反生
這種由于正在執行的任務線程都在等待其它工作隊列中的任務而阻塞的現象稱為 線程饑餓死鎖
活鎖
并未產生線程阻塞,但是由于某種問題的存在,導致無法繼續執行的情況。
1、消息重試。當某個消息處理失敗的時候,一直重試,但重試由于某種原因,比如消息格式不對,導致解析失敗,而它又被重試
這種時候一般是將不可修復的錯誤不要重試,或者是重試次數限定
2、相互協作的線程彼此響應從而修改自己狀態,導致無法執行下去。比如兩個很有禮貌的人在同一條路上相遇,彼此給對方讓路,但是又在同一條路上遇到了。互相之間反復的避讓下去
這種時候可以選擇一個隨機退讓,使得具備一定的隨機性
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://segmentfault.com/a/1190000017134766