多執行緒與併發----讀寫鎖
鎖
1、鎖分為讀鎖和寫鎖
2、多個讀鎖不互斥
3、讀鎖和寫鎖互斥
4、寫鎖與寫鎖互斥
總之,這是由JVM自己控制的,如果你的程式碼只讀取資料,可以多人同時讀,但不能同時寫,那就上讀鎖;若歌你的程式碼修改資料,只能有一個人在寫,且不能同時讀取,那就上寫鎖。
三個執行緒讀資料,三個執行緒寫資料示例:
功能:可以同時讀,讀的時候不能寫,不能同時寫,寫的時候不能讀,讀的時候上讀鎖,讀完解鎖;寫的時候上寫鎖,寫完解鎖。注意finally解鎖
import java.util.Random; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReadWriteLockTest { /**讀寫所使用 * 三個執行緒讀,三個執行緒寫 */ public static void main(String[] args) { //共享物件 final Source source = new Source(); //建立執行緒 for (int i=0; i<3; i++){ //讀 new Thread(new Runnable(){ public void run(){ while (true) source.get(); } }).start(); //寫 new Thread(new Runnable(){ public void run(){ while (true) source.put(new Random().nextInt(999)); } }).start(); } } static class Source { //共享資料 private int data = 0; //要操作同一把鎖上的讀或寫鎖 ReadWriteLock rwl = new ReentrantReadWriteLock(); //讀方法 public void get() { //上讀鎖 rwl.readLock().lock(); try { //獲取資料並輸出 System.out.println("讀——"+Thread.currentThread().getName()+"正在獲取資料。。。"); try { Thread.sleep(new Random().nextInt(6)*1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("讀——"+Thread.currentThread().getName()+"獲取到的資料:"+data); }finally { //解鎖 rwl.readLock().unlock(); } } //寫方法 public void put(int data) { //上寫鎖 rwl.writeLock().lock(); try { //提示資訊 System.out.println("寫——"+Thread.currentThread().getName()+"正在改寫資料。。。"); try { Thread.sleep(new Random().nextInt(6)*1000); } catch (InterruptedException e) { e.printStackTrace(); } this.data = data; System.out.println("寫——"+Thread.currentThread().getName()+"已將資料改寫為:"+data); }finally { //解鎖 rwl.writeLock().unlock(); } } } }
執行結果為:
讀——Thread-0正在獲取資料。。。
讀——Thread-2正在獲取資料。。。
讀——Thread-4正在獲取資料。。。
讀——Thread-0獲取到的資料:0
讀——Thread-4獲取到的資料:0
讀——Thread-2獲取到的資料:0
寫——Thread-3正在改寫資料。。。
寫——Thread-3已將資料改寫為:565
寫——Thread-3正在改寫資料。。。
ReentrantReadWriteLock
構造方法摘要 |
ReentrantReadWriteLock() 使用預設(非公平)的排序屬性建立一個新的 ReentrantReadWriteLock。 |
ReentrantReadWriteLock(boolean fair) 使用給定的公平策略建立一個新的 ReentrantReadWriteLock。 |
方法摘要 | ||||
protected Thread | getOwner() 返回當前擁有寫入鎖的執行緒,如果沒有這樣的執行緒,則返回 null。 | |||
protected Collection<Thread> | getQueuedReaderThreads() 返回一個 collection,它包含可能正在等待獲取讀取鎖的執行緒。 | |||
protected Collection<Thread> | getQueuedThreads() 返回一個 collection,它包含可能正在等待獲取讀取或寫入鎖的執行緒。 | |||
protected Collection<Thread> | getQueuedWriterThreads() 返回一個 collection,它包含可能正在等待獲取寫入鎖的執行緒。 | |||
int | getQueueLength() 返回等待獲取讀取或寫入鎖的執行緒估計數目。 | |||
int | getReadHoldCount() 查詢當前執行緒在此鎖上保持的重入讀取鎖數量。 | |||
int | getReadLockCount() 查詢為此鎖保持的讀取鎖數量。 | |||
protected Collection<Thread> | getWaitingThreads(Condition condition) 返回一個 collection,它包含可能正在等待與寫入鎖相關的給定條件的那些執行緒。 | |||
int | getWaitQueueLength(Condition condition) 返回正等待與寫入鎖相關的給定條件的執行緒估計數目。 | |||
int | getWriteHoldCount() 查詢當前執行緒在此鎖上保持的重入寫入鎖數量。 | |||
boolean | hasQueuedThread(Thread thread) 查詢是否給定執行緒正在等待獲取讀取或寫入鎖。 | |||
boolean | hasQueuedThreads() 查詢是否所有的執行緒正在等待獲取讀取或寫入鎖。 | |||
boolean | hasWaiters(Condition condition) 查詢是否有些執行緒正在等待與寫入鎖有關的給定條件。 | |||
boolean | isFair() 如果此鎖將公平性設定為 ture,則返回 true。 | |||
boolean | isWriteLocked() 查詢是否某個執行緒保持了寫入鎖。 | |||
boolean | isWriteLockedByCurrentThread() 查詢當前執行緒是否保持了寫入鎖。 | |||
readLock() 返回用於讀取操作的鎖。 | ||||
toString() 返回標識此鎖及其鎖狀態的字串。 | ||||
writeLock() 返回用於寫入操作的鎖。 |
JDK幫助文件中的示例用法。下面的程式碼展示瞭如何利用重入來執行升級快取後的鎖降級(為簡單起見,省略了異常處理):
class CachedData { Object data; volatile boolean cacheValid; 資料有沒有標記 ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); void processCachedData() {處理資料 rwl.readLock().lock();先上讀鎖 if (!cacheValid) {如果資料不存在 // Must release read lock before acquiring write lock rwl.readLock().unlock();準備寫資料,需先解除讀鎖 rwl.writeLock().lock();上寫鎖 // Recheck state because another thread might have acquired // write lock and changed state before we did. if (!cacheValid) {再次檢查資料是否存在,防止其他執行緒已經存入資料 data = ... cacheValid = true;寫好資料,改變標記 } // Downgrade by acquiring read lock before releasing write lock 準備釋放寫鎖,資料存在了,釋放後就要使用資料,恢復產生資料前的讀鎖狀態 rwl.readLock().lock(); rwl.writeLock().unlock(); // Unlock write, still hold read } use(data);存在直接使用資料 rwl.readLock().unlock();解除讀鎖 } }
面試題:設計一個快取系統
快取系統:你要取資料,需呼叫我的public Object getData(String key)方法,我要檢查我內部有沒有這個資料,如果有就直接返回,如果沒有,就從資料庫中查詢這個數,查到後將這個資料存入我內部的儲存器中,下次再有人來要這個資料,我就直接返回這個數不用再到資料庫中找了。 你要取資料不要找資料庫,來找我。
class CachedSystem { //快取系統的儲存器 private Map<String, Object> cache = new HashMap<String, Object>(); //取資料方法可能有多個執行緒來取資料,沒有資料的話又會去資料庫查詢,需要互斥 public synchronized Object get(String key) { //先查詢內部儲存器中有沒有要的值 Object value = cache.get(key); if (value==null)//如果沒有,就去資料庫中查詢,並將查到的結果存入內部儲存器中 { value = “aaaa”; //實際程式碼是查詢後的結果 queryDB(key) cache.put(key, value); } return value; } //上面的程式碼每次只能有一個執行緒來查詢,但只有寫的時候才需要互斥,修改如下 //來一個讀寫鎖 ReadWriteLock rwl = new ReentrantReadWriteLock(); public Object get(String key){ //上讀鎖 rwl.readLock().lock(); //先查詢內部儲存器中有沒有要的值 Object value = cache.get(key); if (value==null)//如果沒有,就去資料庫中查詢,並將查到的結果存入內部儲存器中 { //釋放讀鎖 上寫鎖 rwl.readLock().unlock(); rwl.writeLock().lock(); if (value==null)再次進行判斷,防止多個寫執行緒堵在這個地方重複寫 { value = “aaaa”; cache.put(key, value); } //設定完成 釋放寫鎖,恢復讀寫狀態 rwl.readLock().lock(); rwl.writeLock().unlock(); } //釋放讀鎖 rwl.readLock().unlock(); return value; //注意:try finally中unlock } }
相關文章
- 多執行緒系列(十一) -淺析併發讀寫鎖StampedLock執行緒
- 多執行緒與併發-----Lock鎖技術執行緒
- Java多執行緒/併發06、執行緒鎖Lock與ReadWriteLockJava執行緒
- 【多執行緒與高併發3】常用鎖例項執行緒
- 多執行緒與高併發(二)執行緒安全執行緒
- 併發與多執行緒之執行緒安全篇執行緒
- 多執行緒與高併發(一)多執行緒入門執行緒
- 多執行緒併發程式設計“鎖”事執行緒程式設計
- 併發與多執行緒基礎執行緒
- 多執行緒與併發----Semaphere同步執行緒
- java多執行緒與併發 - 併發工具類Java執行緒
- java多執行緒與併發 - 執行緒池詳解Java執行緒
- 【多執行緒與高併發】- 執行緒基礎與狀態執行緒
- Java多執行緒/併發10、不可重入鎖/自旋鎖、可重入鎖Java執行緒
- JAVA多執行緒併發Java執行緒
- 23、Java併發性和多執行緒-重入鎖死Java執行緒
- 多執行緒併發篇——如何停止執行緒執行緒
- Java多執行緒與併發之ThreadLocalJava執行緒thread
- Java高併發與多執行緒(一)-----概念Java執行緒
- Java多執行緒與併發 - 瞭解“monitor”Java執行緒
- Java併發(十六)----執行緒八鎖Java執行緒
- Java高併發與多執行緒(二)-----執行緒的實現方式Java執行緒
- GCD 多執行緒安全 單寫多讀GC執行緒
- Java併發指南1:併發基礎與Java多執行緒Java執行緒
- java 多執行緒 併發 面試Java執行緒面試
- 多執行緒併發鎖分類以及簡單例項執行緒單例
- 多執行緒_鎖執行緒
- Java核心(三)併發中的執行緒同步與鎖Java執行緒
- java併發與執行緒Java執行緒
- Java 併發和多執行緒(一) Java併發性和多執行緒介紹[轉]Java執行緒
- Java多執行緒中執行緒安全與鎖問題Java執行緒
- LINUX多執行緒讀寫同一個檔案 加鎖Linux執行緒
- Java多執行緒與併發基礎面試題Java執行緒面試題
- 【多執行緒與高併發 2】volatile 篇執行緒
- 【多執行緒與高併發】- 淺談volatile執行緒
- JUC之Exchanger-多執行緒與高併發執行緒
- java多執行緒與併發 - Condition(條件)Java執行緒
- 分散式叢集與多執行緒高併發分散式執行緒