聲明:本文是《 Java 7 Concurrency Cookbook 》的第八章, 作者: Javier Fernández González 譯者:鄭玉婷 ?
校對:方騰飛
監控Lock接口
Lock 接口是Java 并發 API提供的最基本的機制來同步代碼塊。它允許定義臨界區。臨界區是代碼塊可以共享資源,但是不能被多個線程同時執行。此機制是通過Lock 接口和 ReentrantLock 類實現的。
在這個指南,你將學習從Lock對象可以獲取的信息和如何獲取這些信息。
準備
指南中的例子是使用Eclipse IDE 來實現的。如果你使用Eclipse 或者其他的IDE,例如NetBeans, 打開并創建一個新的java項目。
怎么做呢…
按照這些步驟來實現下面的例子:
003 | import java.util.Collection; |
004 | import java.util.concurrent.TimeUnit; |
005 | import java.util.concurrent.locks.Lock; |
006 | import java.util.concurrent.locks.ReentrantLock; |
009 | public class MyLock extends ReentrantLock { |
012 | ???? public String getOwnerName() { |
013 | ???????? if ( this .getOwner() == null ) { |
014 | ???????????? return "None" ; |
016 | ???????? return this .getOwner().getName(); |
021 | ???? public Collection<Thread> getThreads() { |
022 | ???????? return this .getQueuedThreads(); |
026 | ???? public class Task implements Runnable { |
029 | ???????? private Lock lock; |
032 | ???????? public Task(Lock lock) { |
033 | ???????????? this .lock = lock; |
038 | ???????? public void run() { |
039 | ???????????? for ( int i = 0 ; i < 5 ; i++) { |
042 | ???????????????? lock.lock(); |
043 | ???????????????? System.out.printf( "%s: Get the Lock.\n" , Thread.currentThread() |
044 | ???????????????????????? .getName()); |
047 | ???????????????? try { |
048 | ???????????????????? TimeUnit.MILLISECONDS.sleep( 500 ); |
049 | ???????????????????? System.out.printf( "%s: Free the Lock.\n" , Thread |
050 | ???????????????????????????? .currentThread().getName()); |
051 | ???????????????? } catch (InterruptedException e) { |
052 | ???????????????????? e.printStackTrace(); |
053 | ???????????????? } finally { |
054 | ???????????????????? lock.unlock(); |
061 | ???? public static void main(String[] args) throws Exception { |
064 | ???????? MyLock lock = new MyLock(); |
067 | ???????? Thread threads[] = new Thread[ 5 ]; |
070 | ???????? for ( int i = 0 ; i < 5 ; i++) { |
071 | ???????????? Task task = lock. new Task(lock); |
072 | ???????????? threads[i] = new Thread(task); |
073 | ???????????? threads[i].start(); |
077 | ???????? for ( int i = 0 ; i < 15 ; i++) { |
080 | ???????????? System.out.printf( "Main: Logging the Lock\n" ); |
081 | ???????????? System.out.printf( "************************\n" ); |
082 | ???????????? System.out.printf( "Lock: Owner : %s\n" , lock.getOwnerName()); |
085 | ???????????? System.out.printf( "Lock: Queued Threads: %s\n" , |
086 | ???????????????????? lock.hasQueuedThreads()); |
087 | ???????????? if (lock.hasQueuedThreads()) { |
088 | ???????????????? System.out.printf( "Lock: Queue Length: %d\n" , |
089 | ???????????????????????? lock.getQueueLength()); |
090 | ???????????????? System.out.printf( "Lock: Queued Threads: " ); |
091 | ???????????????? Collection<Thread> lockedThreads = lock.getThreads(); |
092 | ???????????????? for (Thread lockedThread : lockedThreads) { |
093 | ???????????????????? System.out.printf( "%s " , lockedThread.getName()); |
095 | ???????????????? System.out.printf( "\n" ); |
099 | ???????????? System.out.printf( "Lock: Fairness: %s\n" , lock.isFair()); |
100 | ???????????? System.out.printf( "Lock: Locked: %s\n" , lock.isLocked()); |
101 | ???????????? System.out.printf( "************************\n" ); |
104 | ???????????? TimeUnit.SECONDS.sleep( 1 ); |
它是如何工作的…
在這個指南里,你實現的MyLock類擴展了ReentrantLock類來返回信息,除此之外獲得不到這些信息 ,因為ReentrantLock 類里的數據都是保護類型的。 通過MyLock類實現的方法:
- getOwnerName():只有唯一一個線程可以執行被Lock對象保護的臨界區。鎖存儲了正在執行臨界區的線程。此線程會被ReentrantLock類的保護方法 getOwner()返回。 此方法使用 getOwner() 方法來返回線程的名字。
- getThreads():當線程正在執行臨界區時,其他線程嘗試進入臨界區就會被放到休眠狀態一直到他們可以繼續執行為止。ReentrantLock類保護方法getQueuedThreads() 返回 正在等待執行臨界區的線程list。此方法返回 getQueuedThreads() 方法返回的結果。
我們還使用了 ReentrantLock 類里實現的其他方法:
- hasQueuedThreads():此方法返回 Boolean 值表明是否有線程在等待獲取此鎖
- getQueueLength(): 此方法返回等待獲取此鎖的線程數量
- isLocked(): 此方法返回 Boolean 值表明此鎖是否為某個線程所擁有
- isFair(): 此方法返回 Boolean 值表明鎖的 fair 模式是否被激活
更多…
ReentrantLock 類還有其他方法也是用來獲取Lock對象的信息的:
- getHoldCount(): 返回當前線程獲取鎖的次數
- isHeldByCurrentThread(): 返回 Boolean 值,表明鎖是否為當前線程所擁有