1)Lock與synchronized的區別:java
1)Lock顯示地獲取和釋放鎖: void lock(); // 獲取鎖。 void unlock(); // 釋放鎖。 2)能夠非阻塞的獲取鎖: boolean tryLock(); // 調用該方法後馬上返回,若是能獲取到鎖則返回true,不然返回false; 3)能夠中斷地獲取鎖: void lockInterruptibly() throws InterruptedException; // 在鎖的獲取過程當中,若是獲取鎖的線程被中斷,則拋出中斷異常並返回。 4)能夠超時地獲取鎖: boolean tryLock(long time, TimeUnit unit) throws InterruptedException; // 在time時間內,獲取到鎖返回true,若是獲取鎖的線程被中斷則返回false;超出time時間,返回false。 5)Condition newCondition(); Condition:java.util.concurrent.locks.Condition 1)每一個Condition對象都包含着一個等待隊列,該隊列是Condition對象實現等待/通知功能的關鍵。 2)等待隊列是一個FIFO的隊列,在隊列中的每一個節點都包含了一個線程引用,該線程就是在Condition對象上等待的線程。 3)若是一個線程調用了Condition.await()方法,那麼該線程將會釋放鎖,而且構形成節點加入等待隊列並進入等待狀態。 4)事實上,同步隊列(獲取Lock排隊)和等待隊列(獲取Condition排隊)中節點的類型都是同步器的靜態內部類AbstractQueuedSynchronizer.Node 5)注意:在condition.await()方法調用以前,必須先用lock.lock()方法獲取到鎖。 6)多路通知功能: 在一個Lock對象裏面建立多個Condition實例,線程對象能夠註冊在指定的Condition中,從而能夠有選擇地進行線程通知。能夠先對線程進行分組,而後再喚醒指定組中的線程。 實現:ReentrantLock、ReentrantReadWriteLock、CountDownLatch
2)ReentrantLock(重入鎖):併發
重入: 1)重入是指任意線程在獲取到鎖以後可以再次獲取該鎖而不會被阻塞。 2)在調用lock()方法時,已經獲取到鎖的線程,可以再次調用lock()方法獲取鎖而不被阻塞。 重入的過程: 1)線程再次獲取鎖:鎖須要去識別獲取鎖的線程是否爲當前佔據鎖的線程,若是是,則再次成功獲取。 2)鎖的最終釋放: 1>獲取鎖時須要進行計數自增,計數表示當前鎖被重複獲取的次數,而鎖被釋放時,計數自減,當計數等於0時表示鎖已經成功釋放。 2>線程重複n次獲取了鎖,隨後在釋放n次該鎖後,其它線程可以獲取到該鎖。 支持獲取鎖時的公平性和非公平性選擇: 1)公平鎖保證了鎖的獲取按照FIFO原則,其代價是須要進行大量的線程切換。 2)非公平鎖雖然可能形成線程「飢餓」,可是極少的線程切換,保證了其更大的吞吐量。 ReentrantLock類中封裝的AQS的同步狀態表示鎖被一個線程重複獲取的次數。 舉例: ------------------------------------------ 實現等待/通知的service類: import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class MessageService { private Lock lock = new ReentrantLock(); public Condition conditionA = lock.newCondition(); public Condition conditionB = lock.newCondition(); public void awaitA() { try { lock.lock(); System.out.println("start awaitA, time:" + System.currentTimeMillis() + " ThreadName:" + Thread.currentThread().getName()); conditionA.await(); System.out.println("end awaitA, time:" + System.currentTimeMillis() + " ThreadName:" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void awaitB() { try { lock.lock(); System.out.println("start awaitB, time:" + System.currentTimeMillis() + " ThreadName:" + Thread.currentThread().getName()); conditionB.await(); System.out.println("end awaitB, time:" + System.currentTimeMillis() + " ThreadName:" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void signalAllforA() { try { lock.lock(); System.out.println("signalAllforA, time:" + System.currentTimeMillis() + " ThreadName:" + Thread.currentThread().getName()); conditionA.signalAll(); } finally { lock.unlock(); } } public void signalAllforB() { try { lock.lock(); System.out.println("signalAllforB, time:" + System.currentTimeMillis() + " ThreadName:" + Thread.currentThread().getName()); conditionB.signalAll(); } finally { lock.unlock(); } } } --------------------- 線程A public class ThreadA extends Thread{ private MessageService messageService; public ThreadA(MessageService messageService) { this.messageService = messageService; } [@Override](https://my.oschina.net/u/1162528) public void run() { this.messageService.awaitA(); } } --------------------- 線程B public class ThreadB extends Thread{ private MessageService messageService; public ThreadB(MessageService messageService) { this.messageService = messageService; } [@Override](https://my.oschina.net/u/1162528) public void run() { this.messageService.awaitB(); } } --------------------- 測試類: public class LockTest { public static void main(String[] args) { try { MessageService messageService = new MessageService(); ThreadA threadA = new ThreadA(messageService); threadA.setName("Thread-A"); threadA.start(); ThreadB threadB = new ThreadB(messageService); threadB.setName("Thread-B"); threadB.start(); Thread.sleep(5000); messageService.signalAllforA(); // 運行後,只有ThreadA被喚醒了 } catch (InterruptedException e) { e.printStackTrace(); } } } 結果: start awaitA, time:1497603307947 ThreadName:Thread-A start awaitB, time:1497603307947 ThreadName:Thread-B signalAllforA, time:1497603312947 ThreadName:main end awaitA, time:1497603312947 ThreadName:Thread-A ------------------------------------------
3)ReadWriteLock(讀寫鎖):ide
概念:讀寫鎖維護了一對鎖,一個讀鎖和一個寫鎖,經過分離讀鎖和寫鎖,使得併發性相比通常的獨佔鎖有了很大提高。 源碼: package java.util.concurrent.locks; public interface ReadWriteLock { /** Returns the lock used for reading. */ Lock readLock(); /** Returns the lock used for writing. */ Lock writeLock(); } 說明: 1)讀寫鎖在同一時刻能夠容許多個讀線程訪問,可是在寫線程訪問時,其它的讀線程和寫線程均被阻塞。 2)若是當前線程獲取了寫鎖或者寫鎖未被獲取,則當前線程能夠獲取讀鎖。 3)若是當前線程在獲取讀鎖時,寫鎖已被其餘線程獲取,則進入等待狀態。 4)通常狀況下,讀寫鎖的性能都會比獨佔鎖好,由於大多數場景讀是多於寫的。 5)在讀多於寫的狀況下,讀寫鎖可以提供比獨佔鎖更好的併發性和吞吐量。 實現:ReentrantReadWriteLock 特色: 1)支持公平性選擇 2)支持讀鎖和寫鎖的重入 3)支持鎖降級: 1>鎖降級的概念:先獲取到寫鎖後,再獲取到讀鎖,隨後才釋放寫鎖,最後只持有讀鎖的過程。 2>按照獲取寫鎖、獲取讀鎖、釋放寫鎖的順序進行操做,從而將寫鎖降級爲讀鎖。 說明: 1)若是存在讀鎖,則寫鎖不能被獲取,進入等待狀態。 2)若是其它線程已經獲取了寫鎖,則當前線程不能獲取讀鎖,進入等待狀態。 讀寫狀態的設計: 在一個整型變量上維護多種狀態,就須要「按位切割使用」這個變量,讀寫鎖將變量切分紅了兩個部分,高16位表示讀,低16位表示寫。