1.Lock接口鎖是用來控制多個線程訪問共享資源的方式,通常來講,一個鎖可以防止多個線程同時訪問共享資源。 在Lock出現以前,java程序是靠synchronized關鍵字實現鎖功能的,而Java SE5以後,併發包中新增了Lock接口用來實現鎖功能。它提供了與synchronized關鍵字相似的同步功能,只是在使用時須要顯示地獲取和釋放鎖。有用了鎖獲取與釋放的可操做性、可中斷的獲取鎖以及超時獲取鎖等synchronized關鍵字所不具有的同步特性。 Lock接口提供的synchronized關鍵字所不具有的主要特性 1.嘗試非阻塞地獲取鎖。 2.能被中斷的獲取鎖。獲取到鎖的線程可以響應中斷,當獲取到鎖的線程被中斷,當獲取到鎖的線程被中斷時,中斷異常將會被拋出,同時鎖會釋放。 3.超時獲取鎖 在指定的時間以前獲取鎖,若是截止時間到了仍舊沒法獲取鎖,則返回。java
2.AQS 隊列同步器AbstractQueuedSynchronizer,用來構建鎖或者其餘同步組建的基礎框架。用一個int類型的state成員變量表示同步狀態,經過內置的FIFO隊列來完成資源獲取線程的排隊工做。 同步器的主要使用方法是繼承,子類經過繼承同步器(AQS)並實現它的抽象方法來管理同步狀態,在抽象方法的實現過程當中免不了進行狀態更改。須要同步器提供三個方法getState(),setState()和compareAndSetState()來進行操做,由於他們可以保證狀態的改變是安全的。子類推薦被定義爲自定義同步組件的靜態內部類,同步器自身沒有實現任何同步接口。它僅僅是定義了若干同步狀態獲取和釋放的方法來提供同步組件使用。同步器既能夠支持獨佔式地獲取同步狀態,也能夠支持共享地獲取同步狀態。這樣能夠實現不一樣類型的同步組件(ReentrantLock、ReentrantReadWriteLock和CountDownLatch等)。 隊列同步器的接口與示例 同步器的設計是基於模板方法的,也就是說,使用者須要繼承同步器並從新指定的方法,隨後將同步器組合在自定義同步組件的實現中,並調用同步器提供的模板方法,而這些模板方法將會調用使用者重寫的方法。 重寫同步器指定的方法時,須要使用同步器提供的以下3個方法來訪問或者修改同步狀態。 a) getState() b) setState(int newState) 設置當前同步狀態 c) compareAndSetState(int except,int update):使用CAS設置當前狀態,改方法可以保證狀態設置的原子性。安全
同步器可重寫的方法與描述 boolean tryAcquire(int arg) 獨佔式獲取同步狀態 boolean tryRelease(int arg) 獨佔式釋放同步狀態 int tryAcquireShared(int arg) 共享式獲取同步狀態 boolean tryReleaseShared(int arg) 共享式釋放同步狀態 boolean isHeldExcusively() 當前同步器是否在獨佔模式下被線程佔用併發
實現自定義同步組件時,將會提供同步器提供的模板方法,這些模板方法描述以下 void acquire(int arg) 獨佔式獲取同步狀態,若是當前線程獲取同步狀態成功,則由改方法返回,不然,進入同步隊列等待。 void acquireInterruptibly(int arg) 與acquire(int arg)相同,可是該方法響應中斷。 boolean tryAcquireNanos(int arg,long nanos) 在anquireInterruptibly(int arg)基礎上增長了超時限制 void acquireShared(int arg) 共享獲取同步狀態,若是當前線程獲取同步狀態成功,則由改方法返回,不然,進入同步隊列等待。 void acquireSharedInterruptibly(int arg) 與acquireShared(int arg)相同,可是該方法響應中斷。 boolean tryAcquireSharedNanos(int arg,long nanos) 在anquireSharedInterruptibly(int arg)基礎上增長了超時限制 boolean release(int arg)獨佔式的釋放同步狀態,該方法會在釋放同步狀態以後,將同步隊列中的第一個節點中包含的線程喚醒。 boolean releaseShared(int arg) 共享式的釋放同步狀態框架
Collection<Thread> getQueuedThreads() 獲取等待隊列上的線程集合ui
同步器提供的模板方法基本分爲三類:獨佔模式獲取與釋放同步狀態、共享式獲取與釋放同步狀態和查詢同步隊列的等待線程狀況。線程
class Mutex implments Lock { private static class Sync extends AbstractQueuedSynchronizer { //是否處於佔用狀態 protected boolean isHeldExclusively{ return getState()==1 } //當前狀態爲0的時候獲取鎖 public boolean tryAcquire(int acquires){ if(compareAndSwap(0,1)){ setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } //釋放鎖,將狀態設置爲0 protected boolean tryRelease(int release){ if(getState()==0) throw new IllegalMonitorStateException(); setState(0); setExclusiveOwnerThread(null); return true; } //返回一個Condition 每一個Condition都包含一個condition狀態 Condition newCondition(){ return new ConditionObject(); } }設計
//僅須要將操做代理到Sunc上便可,使用模板方法 private final Sync sync=new Sync(); public void lock(){ sync.lock(); } public boolean tryLock(){ return sync.tryLock(); } ..... } 在Mutex中定義一個靜態內部類代理
隊列同步器的實現分析 1.同步隊列 同步器依賴內部的同步隊列(一個FIFO雙向隊列)來完成同步狀態的管理,當前線程獲取同步狀態失敗後時,同步器將會將當前線程以及等待狀態等信息構形成爲一個節點(Node)並將其加入同步隊列,同時阻塞當前線程,當同步狀態釋放時,會把首節點中的線程喚醒,再次嘗試獲取同步狀態。 2.獨佔式同步狀態獲取與釋放 經過調用acquire(int arg)方法獲取同步狀態,該方法對中斷不敏感,進入同步隊列中,線程被中斷後,線程不會從同步隊列中移除。繼承
3.共享式同步獲取與釋放 共享式獲取與獨佔式獲取最主要的區別在於同一時刻可否有多個線程同時獲取同步狀態。接口
4.獨佔式超時獲取同步狀態 經過調用同步器的doAcquireNanos(int arg,long nanosTimeout)方法能夠超時得到同步狀態,即在指定的時間段內獲取同步狀態。若是獲取到同步狀態返回tue,不然返回false. 響應中斷的同步狀態獲取過程。在Java5以前,當一個線程獲取不到鎖而被阻塞在synchronizer以外時,對線程進行中斷操做,此時改線程的中斷標誌位被修改,可是線程依舊會阻塞在synchronized上,等待着獲取鎖。在Java5中,同步器提供了acquireInterruptibly(int arg)方法,這個方法在等待獲取同步鎖狀態時,若是當前線程被中斷,會當即返回,並拋出InterruptException。 超時獲取同步狀態能夠被視爲響應中斷獲取同步狀態過程的「加強版」,doAcquireNanos(int arg,long nanosTimeOut)方法在支持響應中斷的基礎上,增長了超時獲取的特性。