Java中的ReadWriteLock讀寫鎖詳解
ReadWriteLock
ReadWriteLock也是一個(gè)接口,提供了readLock和writeLock兩種鎖的操作機(jī)制,一個(gè)資源可以被多個(gè)線程同時(shí)讀,或者被一個(gè)線程寫,但是不能同時(shí)存在讀和寫線程。
讀鎖:共享鎖 readLock
**寫鎖:**獨(dú)占鎖 writeLock
讀寫鎖 : 一個(gè)資源可以被多個(gè)讀的線程進(jìn)行訪問 ,或者可以被一個(gè)寫的線程訪問,
但是不能同時(shí)存在讀和寫進(jìn)程 ,讀寫互斥,讀讀共享。
讀的時(shí)候可以多個(gè)線程一起讀
寫的時(shí)候只能一個(gè)線程寫
使用示例:
向map中添加和讀取值
public class ReadWriteLock { public static void main(String[] args) { MyCache myCache = new MyCache(); //十個(gè)寫線程 for (int i = 0; i < 10; i++) { final int temp=i; new Thread(() -> { myCache.put(temp+"",temp+""); }, String.valueOf(i)).start(); } //十個(gè)讀線程 for (int i = 0; i < 10; i++) { final int temp=i; new Thread(() -> { myCache.get(temp+""); }, String.valueOf(i)).start(); } } } /** * 自定義緩存 */ class MyMap { private volatile Map<String, Object> map = new HashMap<>(); //存入值 public void put(String key, Object value) { System.out.println(Thread.currentThread().getName() + "寫入" + key); map.put(key, value); System.out.println(Thread.currentThread().getName() + "寫入完成"); } //取值 public void get(String key) { System.out.println(Thread.currentThread().getName() + "讀取" + key); Object o = map.get(key); System.out.println(Thread.currentThread().getName() + "讀取完成"); } }
我們可以看到1寫入跟寫入完成之間插入了4線程 這是不對(duì)的
于是我們加入讀寫鎖
加鎖
lock.writeLock().lock(); lock.readLock().lock();
解鎖
lock.writeLock().unlock(); lock.readLock().unlock();
class MyCacheLock { private volatile Map<String, Object> map = new HashMap<>(); //讀寫鎖 :更加細(xì)粒度的控制 private ReadWriteLock lock = new ReentrantReadWriteLock(); //存入值 寫的時(shí)候只希望同時(shí)只有一個(gè)線程寫 public void put(String key, Object value) { //加寫鎖 lock.writeLock().lock(); try { System.out.println(Thread.currentThread().getName() + "寫入" + key); map.put(key, value); System.out.println(Thread.currentThread().getName() + "寫入完成"); } catch (Exception e) { } finally { lock.writeLock().unlock(); } } //取值 讀所有人都可以讀 public void get(String key) { //加讀鎖 lock.readLock().lock(); try { System.out.println(Thread.currentThread().getName() + "讀取" + key); Object o = map.get(key); System.out.println(Thread.currentThread().getName() + "讀取完成"); } catch (Exception e) { } finally { lock.readLock().unlock(); } } }
讀寫鎖的演變
一、無鎖
無鎖狀態(tài)多線程搶占資源 會(huì)出現(xiàn)問題
二、加鎖
synchronized和reentrantLock
都是獨(dú)占鎖 每次只能一個(gè)線程來操作
讀讀 一個(gè)線程 只能一個(gè)人讀
讀寫 一個(gè)線程
寫寫 一個(gè)線程
三、讀寫鎖
ReentrantReadWriteLock
讀讀可以共享,提升性能 同時(shí)多人讀
寫寫 一個(gè)線程
缺點(diǎn):
1.造成鎖的饑餓,可能一直讀沒有寫的操作
2.寫的時(shí)候,自己線程可以讀,讀的時(shí)候,哪個(gè)線程都不可以寫
鎖降級(jí)
鎖降級(jí):將寫入鎖降級(jí)為讀鎖 讀鎖不能升級(jí)為寫鎖
獲取寫鎖—>獲取讀鎖—>釋放寫鎖—>釋放讀鎖
示例
public class Downgrade { public static void main(String[] args) { //可重入讀寫鎖對(duì)象 ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); //讀鎖 ReentrantReadWriteLock.ReadLock readLock = lock.readLock(); //寫鎖 ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock(); //鎖降級(jí) //獲取寫鎖 writeLock.lock(); System.out.println("飛飛"); //獲取讀鎖 readLock.lock(); System.out.println("read讀取"); //解鎖 writeLock.unlock(); readLock.unlock(); } }
但是我們不可以在讀鎖中獲取寫鎖
示例2:
public class Downgrade { public static void main(String[] args) { //可重入讀寫鎖對(duì)象 ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); //讀鎖 ReentrantReadWriteLock.ReadLock readLock = lock.readLock(); //寫鎖 ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock(); //鎖降級(jí) //獲取讀鎖 readLock.lock(); System.out.println("read讀取"); //獲取寫鎖 writeLock.lock(); System.out.println("飛飛"); //解鎖 writeLock.unlock(); readLock.unlock(); } }
不可以在讀鎖中寫 不會(huì)停止
到此這篇關(guān)于Java中的ReadWriteLock讀寫鎖詳解的文章就介紹到這了,更多相關(guān)ReadWriteLock讀寫鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring框架的環(huán)境搭建和測(cè)試實(shí)現(xiàn)
這篇文章主要介紹了Spring框架的環(huán)境搭建和測(cè)試實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10Java實(shí)現(xiàn)任務(wù)超時(shí)處理方法
任務(wù)超時(shí)處理是比較常見的需求,Java中對(duì)超時(shí)任務(wù)的處理有兩種方式,在文中給大家詳細(xì)介紹,本文重點(diǎn)給大家介紹Java實(shí)現(xiàn)任務(wù)超時(shí)處理方法,需要的朋友可以參考下2019-06-06MyBatis-Plus使用ActiveRecord(AR)實(shí)現(xiàn)CRUD
本文將結(jié)合實(shí)例代碼,介紹MyBatis-Plus使用ActiveRecord(AR)實(shí)現(xiàn)CRUD,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07Java中Caffeine本地緩存項(xiàng)目實(shí)例
這篇文章主要介紹了Java中Caffeine本地緩存項(xiàng)目實(shí)例,Caffeine是一個(gè)高性能Java 緩存庫(kù),使用Java8對(duì)Guava緩存重寫版本,在Spring Boot 2.0中將取代Guava,使用spring.cache.cache-names屬性可以在啟動(dòng)時(shí)創(chuàng)建緩存,需要的朋友可以參考下2023-10-10分析設(shè)計(jì)模式之模板方法Java實(shí)現(xiàn)
所謂模板方法模式,就是一個(gè)對(duì)模板的應(yīng)用,就好比老師出試卷,每個(gè)人的試卷都是一樣的,這個(gè)原版試卷就是一個(gè)模板,可每個(gè)人寫在試卷上的答案都是不一樣的,這就是模板方法模式。它的主要用途在于將不變的行為從子類搬到超類,去除了子類中的重復(fù)代碼2021-06-06解決Properties屬性文件中的值有等號(hào)和換行的小問題
這篇文章主要介紹了解決Properties屬性文件中的值有等號(hào)有換行的小問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08mybatis-xml映射文件及mybatis動(dòng)態(tài)sql詳解
XML映射文件的名稱與Mapper接口名稱一致,并且將XML映射文件和Mapper接口放置在相同包下(同包同名),這篇文章主要介紹了mybatis-xml映射文件及mybatis動(dòng)態(tài)sql的相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧2024-12-12