1. 程式人生 > >java併發程式設計(六)之讀寫鎖

java併發程式設計(六)之讀寫鎖

一、讀寫鎖

我們知道在多個執行緒訪問同一個資料的時候是存線上程安全問題的,而在僅僅是讀取資料的時候,是沒有安全問題的,那麼多個執行緒同時讀取資料我們就可以讓其不互斥;而多個執行緒都在修改(寫)資料或有的在讀取有的在寫入的時候再讓其互斥,這樣不但保證執行緒安全而且提高效能。

ReadWriteLock 維護了一對相關的鎖,一個用於只讀操作,另一個用於寫入操作。只要沒有 writer,讀取鎖可以由多個 reader 執行緒同時保持。寫入鎖是獨佔的。

與互斥鎖(讀讀互斥,讀寫互斥)相比,讀-寫鎖允許對共享資料進行更高級別的併發訪問。雖然一次只有一個執行緒(writer 執行緒)可以修改共享資料,但在許多情況下,任何數量的執行緒可以同時讀取共享資料(reader 執行緒),讀-寫鎖利用了這一點。從理論上講,與互斥鎖相比,使用讀-寫鎖所允許的併發性增強將帶來更大的效能提高。

二、讀寫鎖特性

1.重入
此鎖允許 reader 和 writer 按照 ReentrantLock 的樣式重新獲取讀取鎖或寫入鎖。在寫入執行緒保持的所有寫入鎖都已經釋放後,才允許重入 reader 使用它們。

此外,writer 可以獲取讀取鎖,但反過來則不成立。在其他應用程式中,當在呼叫或回撥那些在讀取鎖狀態下執行讀取操作的方法期間保持寫入鎖時,重入很有用。如果 reader 試圖獲取寫入鎖,那麼將永遠不會獲得成功。

2.鎖降級

重入還允許從寫入鎖降級為讀取鎖,其實現方式是:先獲取寫入鎖,然後獲取讀取鎖,最後釋放寫入鎖。但是,從讀取鎖升級到寫入鎖是不可能的。

3.鎖獲取的中斷

讀取鎖和寫入鎖都支援鎖獲取期間的中斷。

4.Condition 支援

寫入鎖提供了一個 Condition 實現,對於寫入鎖來說,該實現的行為與 ReentrantLock.newCondition() 提供的 Condition 實現對 ReentrantLock 所做的行為相同。當然,此 Condition 只能用於寫入鎖。

讀取鎖不支援 Condition,readLock().newCondition() 會丟擲 UnsupportedOperationException。

package com.dason.second;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 模擬高併發從快取中獲取資料,若快取中沒有,則查詢資料庫
 * @author Dason
 *
 */
public class CacheDemo {

	private Map<String, Object> cache = new HashMap<String, Object>();
	private ReadWriteLock rwl = new ReentrantReadWriteLock();
	
	public static void main(String[] args) {
		new Thread() {
			public void run() {
				Object obj = new CacheDemo().getData("a");
				System.out.println(obj);
			};
		}.start();
	}
	
	public  Object getData(String key){
		//1.加上讀鎖
		rwl.readLock().lock();
		Object value = null;
		try{
			value = cache.get(key);
			if(value == null){
				//2.若快取中沒有資料,釋放讀鎖,
				rwl.readLock().unlock();
				//3.加上寫鎖.若多個執行緒進來執行到這一步,一個上鎖成功,其他執行緒阻塞
				//與解決單例模中懶漢模式的執行緒安全的方式一樣
				rwl.writeLock().lock();//①
				try{
					//3.這個判斷避免多個執行緒進來執行①時後重複查詢資料庫
					if(value==null){
						//為value 賦值,即寫操作.
						value = "aaaa";//實際是去queryDB();
					}
					//4.鎖降級,寫鎖變為讀鎖.
					rwl.readLock().lock();
				}finally{
					rwl.writeLock().unlock();
				}
			}
			//使用value,這裡不提供具體實現,因為其不是重點
			//use(value);
		}finally{
			rwl.readLock().unlock();
		}
		return value;
	}
}

相關推薦

java併發程式設計

一、讀寫鎖我們知道在多個執行緒訪問同一個資料的時候是存線上程安全問題的,而在僅僅是讀取資料的時候,是沒有安全問題的,那麼多個執行緒同時讀取資料我們就可以讓其不互斥;而多個執行緒都在修改(寫)資料或有的在讀取有的在寫入的時候再讓其互斥,這樣不但保證執行緒安全而且提高效能。Rea

Java併發程式設計Lock介面

一、Lock介面的引入 由於synchronized關鍵字有些缺陷,如無法響應中斷等,出現了Lock介面。相對於synchronized,Lock有如下補充: Lock可以響應中斷; Lock可以得知執行緒是否已經獲得鎖; Lock可以提供更為複雜的讀寫鎖,以應對讀寫同時存

Java併發程式設計阻塞佇列

前言 在 Android多執行緒(一)執行緒池這篇文章時,當我們要建立ThreadPoolExecutor的時候需要傳進來一個型別為BlockingQueue的引數,它就是阻塞佇列,在這一篇文章裡我們會介紹阻塞佇列的定義、種類、實現原理以及應用。 1

java併發程式設計執行緒倒計數存器CountDownLatch

一、定義一個同步輔助類,在完成一組正在其他執行緒中執行的操作之前,它允許一個或多個執行緒一直等待。用給定的計數 初始化 CountDownLatch。由於呼叫了 countDown() 方法,所以在當前計數到達零之前,await 方法會一直受阻塞。之後,會釋放所有等待的執行緒

Java併發程式設計-Phaser

phaser         英文意思移相器,相位器,表示“階段器”,用來解決控制多個執行緒分階段共同完成任務的情景問題,其作用相比CountDownLatch和CyclicBarrier更加靈活。如100個人參加高考需要考四場考試,早上考語文,需要等100人都

基本執行緒同步使用/同步資料訪問

宣告:本文是《 Java 7 Concurrency Cookbook 》的第二章,作者: Javier Fernández González     譯者:許巧輝 使用讀/寫鎖同步資料訪問 鎖所提供的最重要的改進之一就是ReadWriteLock介面和唯一 一個實現它的ReentrantRe

java網路socket程式設計HTTP請求/響應報文

介紹 http報文包含請求報文和響應報文2種報文,他們都包含起始行、首部欄位、主體三部分。其中,請求報文為客戶端向伺服器端請求資源時傳送的http報文位請求包含,而響應報文為從伺服器端發往客戶端的報文

Java併發程式設計1:可重入內建

每個Java物件都可以用做一個實現同步的鎖,這些鎖被稱為內建鎖或監視器鎖。執行緒在進入同步程式碼塊之前會自動獲取鎖,並且在退出同步程式碼塊時會自動釋放鎖。獲得內建鎖的唯一途徑就是進入由這個鎖保護的同步程式碼塊或方法。 當某個執行緒請求一個由其他執行緒持有的鎖時,發出請求的執行緒就會阻塞。然而,由於內建鎖是可

Java併發程式設計2:執行緒中斷含程式碼

使用interrupt()中斷執行緒當一個執行緒執行時,另一個執行緒可以呼叫對應的Thread物件的interrupt()方法來中斷它,該方法只是在目標執行緒中設定一個標誌,表示它已經被中斷,並立即返回。這裡需要注意的是,如果只是單純的呼叫interrupt()方法,執行緒並沒有實際被中斷,會繼續往下執行。

Java併發程式設計3:執行緒掛起、恢復與終止的正確方法含程式碼

JAVA大資料中高階架構 2018-11-06 14:24:56掛起和恢復執行緒Thread 的API中包含兩個被淘汰的方法,它們用於臨時掛起和重啟某個執行緒,這些方法已經被淘汰,因為它們是不安全的,不穩定的。如果在不合適的時候掛起執行緒(比如,鎖定共享資源時),此時便可能會發生死鎖條件——其他執行緒在等待該

Java併發程式設計4:守護執行緒與執行緒阻塞的四種情況

守護執行緒Java中有兩類執行緒:User Thread(使用者執行緒)、Daemon Thread(守護執行緒) 使用者執行緒即執行在前臺的執行緒,而守護執行緒是執行在後臺的執行緒。 守護執行緒作用是為其他前臺執行緒的執行提供便利服務,而且僅在普通、非守護執行緒仍然執行時才需要,比如垃圾回收執行緒就是一個

Java併發程式設計6:Runnable和Thread實現多執行緒的區別(含程式碼)

Java中實現多執行緒有兩種方法:繼承Thread類、實現Runnable介面,在程式開發中只要是多執行緒,肯定永遠以實現Runnable介面為主,因為實現Runnable介面相比繼承Thread類有如下優勢: 1、可以避免由於Java的單繼承特性而帶來的侷限; 2、增強程式的健壯性,程式碼能夠被多個執行

Java併發程式設計7:使用synchronized獲取互斥的幾點說明

在併發程式設計中,多執行緒同時併發訪問的資源叫做臨界資源,當多個執行緒同時訪問物件並要求操作相同資源時,分割了原子操作就有可能出現數據的不一致或資料不完整的情況,為避免這種情況的發生,我們會採取同步機制,以確保在某一時刻,方法內只允許有一個執行緒。 採用synchronized修飾符實現的同步機制叫做互斥鎖

Java併發程式設計6- J.U.C元件拓展

J.U.C-FutureTask 在Java中一般通過繼承Thread類或者實現Runnable介面這兩種方式來建立執行緒,但是這兩種方式都有個缺陷,就是不能在執行完成後獲取執行的結果,因此Java 1.5之後提供了Callable和Future介面,通過它們就可以在任務執行完畢之後得到任務的執行結果。

Java併發程式設計8:多執行緒環境中安全使用集合API含程式碼

Java併發程式設計(8):多執行緒環境中安全使用集合API(含程式碼)JAVA大資料中高階架構 2018-11-09 14:44:47在集合API中,最初設計的Vector和Hashtable是多執行緒安全的。例如:對於Vector來說,用來新增和刪除元素的方法是同步的。如果只有一個執行緒與Vector的例

Java併發程式設計9:死含程式碼

JAVA大資料中高階架構 2018-11-10 14:04:32當執行緒需要同時持有多個鎖時,有可能產生死鎖。考慮如下情形: 執行緒A當前持有互斥所鎖lock1,執行緒B當前持有互斥鎖lock2。接下來,當執行緒A仍然持有lock1時,它試圖獲取lock2,因為執行緒B正持有lock2,因此執行緒A會阻塞等

Java併發程式設計10:使用wait/notify/notifyAll實現執行緒間通訊的幾點重要說明

在Java中,可以通過配合呼叫Object物件的wait()方法和notify()方法或notifyAll()方法來實現執行緒間的通訊。線上程中呼叫wait()方法,將阻塞等待其他執行緒的通知(其他執行緒呼叫notify()方法或notifyAll()方法),線上程中呼叫notify()方法或notifyAl

Java併發程式設計1

1.執行緒建立方式: 1.1繼承 Thread 建立執行緒 繼承 java.lang.Thread 類建立執行緒是最簡單的一種方法,也最直接。下面建立一個MyThread1 類,繼承 Thread,重寫其 run()方法。並在 main()方法中建立多個併發執行緒 publi

Java併發程式設計Condition介面

一、Condition介面簡介 java.util.concurrent.locks.Condition是java併發包中的一個介面,是為配合Lock提供的執行緒等待/通知功能。我們知道Object的監視器方法wait()和notify()配合sychronized關鍵字一樣可以實現等待/通知機

Java併發程式設計ReentrantReadWriteLock

一、ReentrantReadWriteLock簡介 ReentrantReadWriteLock允許同一時間有一個寫執行緒或多個讀執行緒,滿足了對讀寫併發控制有不同需求的場景,相對於排他鎖,提高了併發性。在實際應用中,大部分情況下對共享資料(如快取)的訪問都是讀操作遠多於寫操作,因此JDK提供