當線程請求内部鎖時,如果鎖已經被占用,則請求線程必須無條件等待,這往往會造成很多奇怪問題,互相等待是造成死鎖的重要原因之一,著名的哲學家就餐問題就是個典型的案例。新的Lock鎖提供了嘗試擷取鎖失敗自動放棄的方法tryLock(),具有更完善的錯誤恢複機制。
1
2
<code>boolean</code> <code>tryLock();</code>
<code>boolean</code> <code>tryLock(</code><code>long</code> <code>time, TimeUnit unit) </code><code>throws</code> <code>InterruptedException;</code>
Lock接口定義了兩個重載tryLock()函數,第一個函數表示如果鎖可用則立即獲得鎖并傳回true,如果請求的鎖目前不可用則立即放棄并傳回false;第二個函數表示如果請求的鎖目前可用則立即獲得鎖并傳回true,如果鎖不可用則等待指定的時間,在等待期間,線程可能被中斷,可能獲得鎖,如果等待時間結束還未擷取到鎖則自動放棄并傳回false,明顯相對第一個函數提供了更多的靈活性。
當然我們還可以自己利用循環輪詢調用tryLock(),以實作輪詢鎖等,實作更多的靈活機制,這就是Lock相對内部鎖的好處,特别是當線程需要同時擷取多把不同鎖時,tryLock()大有用處。
舉一個實際簡單應用場景,假設我們有個定時任務,定時清理垃圾,但每次清理垃圾耗費的時間可能不同,如果新任務發現上個任務還沒執行完就自己結束,因為不需要這次任務。其實ScheduledExecutorService.scheduleAtFixedRate()函數就提供這樣的功能,每個定時任務都是等上個任務完成才開始執行。
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<code>import</code> <code>java.util.concurrent.Executors;</code>
<code>import</code> <code>java.util.concurrent.ScheduledExecutorService;</code>
<code>import</code> <code>java.util.concurrent.TimeUnit;</code>
<code>import</code> <code>java.util.concurrent.locks.Lock;</code>
<code>import</code> <code>java.util.concurrent.locks.ReentrantLock;</code>
<code>public</code> <code>class</code> <code>TestTryLock {</code>
<code> </code><code>private</code> <code>Lock mLock;</code>
<code> </code><code>private</code> <code>volatile</code> <code>boolean</code> <code>isTimeoutEnabled;</code>
<code> </code>
<code> </code><code>public</code> <code>TestTryLock(){</code>
<code> </code><code>this</code><code>.mLock = </code><code>new</code> <code>ReentrantLock();</code>
<code> </code><code>this</code><code>.isTimeoutEnabled = </code><code>false</code><code>;</code>
<code> </code><code>}</code>
<code> </code><code>public</code> <code>void</code> <code>clearRubbish() </code><code>throws</code> <code>InterruptedException{</code>
<code> </code><code>if</code><code>(mLock.tryLock()){</code>
<code> </code><code>try</code><code>{</code>
<code> </code><code>System.out.println(Thread.currentThread().getName() + </code><code>":get the lock successfully."</code><code>);</code>
<code> </code><code>int</code> <code>estTime = (</code><code>int</code><code>) (</code><code>10</code> <code>* Math.random());</code>
<code> </code><code>System.out.println(Thread.currentThread().getName() + </code><code>":estimate time for finish job:"</code> <code>+ estTime);</code>
<code> </code><code>TimeUnit.SECONDS.sleep(estTime);</code>
<code> </code><code>}</code>
<code> </code><code>finally</code><code>{</code>
<code> </code><code>mLock.unlock();</code>
<code> </code><code>} </code>
<code> </code><code>}</code>
<code> </code><code>else</code><code>{</code>
<code> </code><code>System.out.println(Thread.currentThread().getName() + </code><code>":failed to get the lock."</code><code>);</code>
<code> </code><code>} </code>
<code> </code><code>public</code> <code>void</code> <code>clearRubbishWithTimeout() </code><code>throws</code> <code>InterruptedException{</code>
<code> </code><code>if</code><code>(mLock.tryLock(</code><code>2</code><code>, TimeUnit.SECONDS)){</code>
<code> </code><code>System.out.println(Thread.currentThread().getName() + </code><code>":get the lock successfully by waiting 2 seconds."</code><code>);</code>
<code> </code><code>System.out.println(Thread.currentThread().getName() + </code><code>":failed to get the lock after waiting 2 seconds."</code><code>);</code>
<code> </code><code>private</code> <code>class</code> <code>Worker </code><code>implements</code> <code>Runnable{</code>
<code> </code><code>@Override</code>
<code> </code><code>public</code> <code>void</code> <code>run() {</code>
<code> </code><code>try</code> <code>{</code>
<code> </code><code>if</code><code>(isTimeoutEnabled){</code>
<code> </code><code>clearRubbishWithTimeout();</code>
<code> </code><code>}</code>
<code> </code><code>else</code><code>{</code>
<code> </code><code>clearRubbish();</code>
<code> </code><code>} </code>
<code> </code>
<code> </code><code>isTimeoutEnabled = !isTimeoutEnabled;</code>
<code> </code><code>} </code><code>catch</code> <code>(InterruptedException e) {</code>
<code> </code><code>e.printStackTrace();</code>
<code> </code><code>private</code> <code>class</code> <code>TimerWorker </code><code>implements</code> <code>Runnable{</code>
<code> </code><code>new</code> <code>Thread(</code><code>new</code> <code>Worker()).start();</code>
<code> </code><code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) {</code>
<code> </code><code>TestTryLock testTryLock = </code><code>new</code> <code>TestTryLock();</code>
<code> </code><code>ScheduledExecutorService service = Executors.newScheduledThreadPool(</code><code>1</code><code>);</code>
<code> </code><code>service.scheduleAtFixedRate(testTryLock. </code><code>new</code> <code>TimerWorker(), </code><code>0</code><code>, </code><code>3</code><code>, TimeUnit.SECONDS); </code>
<code>}</code>
本文轉自sarchitect 51CTO部落格,原文連結:http://blog.51cto.com/stevex/1301077,如需轉載請自行聯系原作者