天天看點

Lock應用之 嘗試鎖擷取

當線程請求内部鎖時,如果鎖已經被占用,則請求線程必須無條件等待,這往往會造成很多奇怪問題,互相等待是造成死鎖的重要原因之一,著名的哲學家就餐問題就是個典型的案例。新的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,如需轉載請自行聯系原作者