欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的ReentrantReadWriteLock實現(xiàn)原理詳解

 更新時間:2024年01月13日 09:51:26   作者:java架構(gòu)師-太陽  
這篇文章主要介紹了Java中的ReentrantReadWriteLock實現(xiàn)原理詳解,讀寫鎖實現(xiàn)了接口ReadWriteLock,適合于讀多寫少的情況,支持公平鎖和非公平鎖,支持可沖入(進(jìn)入讀鎖后可再進(jìn)入讀鎖,進(jìn)入寫鎖后可再進(jìn)入寫鎖和讀鎖),需要的朋友可以參考下

介紹

讀寫鎖

  • 實現(xiàn)了接口ReadWriteLock
  • 適合于讀多寫少的情況
  • 支持公平鎖和非公平鎖
  • 支持可沖入(進(jìn)入讀鎖后可再進(jìn)入讀鎖,進(jìn)入寫鎖后可再進(jìn)入寫鎖和讀鎖)
  • 支持可沖入和公平與非公平

缺點(diǎn)

(1) 寫鎖饑餓問題,讀的線程很多,寫的線程搶占不到鎖,就一直搶占不到鎖,就饑餓

(2) 鎖降級,獲取寫鎖后又再次獲取讀鎖(重入),釋放了寫鎖之后就變成了讀鎖,就是鎖降級

內(nèi)部接口

Sync/ReadLock/WriteLock/FairSync/NonfairSync 是其內(nèi)部類 下面圖有問題,ReadWriteLock沒有實現(xiàn)Lock

在這里插入圖片描述

代碼演示

public class Lock {   
   public static void main(String[] args) {
      new Thread(new Runnable() {
         @Override
         public void run() {
            for (int i = 0; i < 10; i++) {
               Lock.put(i + "", i + "");
            }
         }
      }).start();
      new Thread(new Runnable() {
         @Override
         public void run() {
            for (int i = 0; i < 10; i++) {
               Lock.get(i + "");
            }
         }
      }).start();
   }
   static Map<String, Object> map = new HashMap<String, Object>();
   static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
   static java.util.concurrent.locks.Lock readLock = readWriteLock.readLock();
   static java.util.concurrent.locks.Lock writeLock = readWriteLock.writeLock();
   public static final Object get(String key) {
      readLock.lock();
      try {
         System.out.println("正在做讀的操作,key:" + key + "開始");
         Thread.sleep(100);
         Object object = map.get(key);
         System.out.println("正在做讀的操作,key:" + key + "結(jié)束");
         System.out.println();
         return object;
      } catch (InterruptedException e) {
         e.printStackTrace();
      } finally {
         readLock.unlock();
      }
      return key;
   }
   public static final Object put(String key, Object value) {
      writeLock.lock();
      try {
         System.out.println("正在做寫的操作,key:" + key + ",value:" + value + "開始");
         Thread.sleep(100);
         Object object = map.put(key, value);
         System.out.println("正在做寫的操作,key:" + key + ",value:" + value + "結(jié)束");
         System.out.println();
         return object;
      } catch (InterruptedException e) {
         e.printStackTrace();
      } finally {
         writeLock.unlock();
      }
      return value;
   }
   public static final void clear() {
      writeLock.lock();
      try {
         map.clear();
      } finally {
         writeLock.unlock();
      }
   }
}
class MyResource {

    Map<String,String> map = new HashMap<>();
    Lock lock = new ReentrantLock();
    ReadWriteLock rwLock = new ReentrantReadWriteLock();

    public void write(String key ,String value) {
        rwLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"\t"+"正在寫入");
            map.put(key,value);
            //暫停毫秒
            try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println(Thread.currentThread().getName()+"\t"+"完成寫入");
        }finally {
            rwLock.writeLock().unlock();
        }
    }

    public void read(String key) {
        rwLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"\t"+"正在讀取");
            String result = map.get(key);

            // 暫停2000毫秒,演示讀鎖沒有完成之前,寫鎖無法獲得
            try { TimeUnit.MILLISECONDS.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println(Thread.currentThread().getName()+"\t"+"完成讀取"+"\t"+result);
        }finally {
            rwLock.readLock().unlock();
        }
    }


}


/**
 * @auther zzyy
 * @create 2022-04-08 18:18
 */
public class ReentrantReadWriteLockDemo {
    public static void main(String[] args) {
        MyResource myResource = new MyResource();

        for (int i = 1; i <=10; i++) {
            int finalI = i;
            new Thread(() -> {
                myResource.write(finalI +"", finalI +"");
            }, String.valueOf(i)).start();
        }

        for (int i = 1; i <=10; i++) {
            int finalI = i;
            new Thread(() -> {
                myResource.read(finalI +"");
            },String.valueOf(i)).start();
        }

        // 暫停幾秒鐘線程
        try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }

        // 在讀鎖沒有完成時, 寫鎖不能寫入
        for (int i = 1; i <=3; i++) {
            int finalI = i;
            new Thread(() -> {
                myResource.write(finalI +"", finalI +"");
            },"新寫鎖線程->"+String.valueOf(i)).start();
        }
    }
}

實現(xiàn)原理

從表面來看,ReadLock和WriteLock是兩把鎖,實際上它只是同一把鎖的兩個視圖而已。

什么叫兩個視圖呢?可以理解為是一把鎖,線程分成兩類:讀線程和寫線程。讀線程和寫線程之間不互斥(可以同時拿到這把鎖),讀線程之間不互斥,寫線程之間互斥

從下面的構(gòu)造方法也可以看出,readerLock和writerLock實際共用同一個sync對象。

sync對象同互斥鎖一樣,分為非公平和公平兩種策略,并繼承自AQS

public ReentrantReadWriteLock() {
    this(false);           
}
public ReentrantReadWriteLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();    // fair為false使用非公平鎖,true使用公平鎖
    readerLock = new ReadLock(this);
    writerLock = new WriteLock(this);
}

同互斥鎖一樣,讀寫鎖也是用state變量來表示鎖狀態(tài)的。只是state變量在這里的含義和互斥鎖完全不同。在內(nèi)部類Sync中,對state變量進(jìn)行了重新定義,如下所示:

abstract static class Sync extends AbstractQueuedSynchronizer {
  // ...
  static final int SHARED_SHIFT = 16;
  static final int SHARED_UNIT = (1 << SHARED_SHIFT);
  static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
  static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
  // 持有讀鎖的線程的重入次數(shù)
  static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
  // 持有寫鎖的線程的重入次數(shù)
  static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
  // ...
}

把 state變量拆成兩半,低16位用來記錄寫鎖。但同一時間既然只能有一個線程寫,為什么還需要16位呢?這是因為一個寫線程可能多次重入。

例如,低16位的值等于5,表示一個寫線程重入了5次 高16位,用來讀鎖。

如高16位的值等于5,既可以表示5個讀線程都拿到了該鎖;也可以表示一個讀線程重入了5次

為什么要把一個int類型變量拆成兩半,而不是用兩個int型變量分別表示讀鎖和寫鎖的狀態(tài)呢?因為無法用一次CAS同時操作兩個int變量,所以用了一個int型的高16位和低16位分別表示讀鎖和寫鎖的狀態(tài)

當(dāng)state=0時,說明既沒有線程持有讀鎖,也沒有線程持有寫鎖;當(dāng)state != 0時,要么有線程持有讀鎖,要么有線程持有寫鎖,兩者不能同時成立,因為讀和寫互斥。

這時再進(jìn)一步通過sharedCount(state)和exclusiveCount(state)判斷到底是讀線程還是寫線程持有了該鎖

到此這篇關(guān)于Java中的ReentrantReadWriteLock實現(xiàn)原理詳解的文章就介紹到這了,更多相關(guān)ReentrantReadWriteLock原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于ComponentScan注解的掃描范圍及源碼解析

    基于ComponentScan注解的掃描范圍及源碼解析

    這篇文章主要介紹了基于ComponentScan注解的掃描范圍及源碼解析,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • 一篇文章學(xué)會java死鎖與CPU 100%的排查

    一篇文章學(xué)會java死鎖與CPU 100%的排查

    這篇文章主要介紹了一篇文章學(xué)會java死鎖與CPU 100%的排查,文中主要介紹了Java死鎖以及服務(wù)器CPU占用率達(dá)到100%時的排查和解決方法,感興趣的朋友一起來看一看吧
    2021-08-08
  • microlog4android將Android Log日志寫到SD卡文件中實現(xiàn)方法

    microlog4android將Android Log日志寫到SD卡文件中實現(xiàn)方法

    這篇文章主要介紹了microlog4android將Android Log日志寫到SD卡文件中實現(xiàn)方法的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • Spring實現(xiàn)在非controller中獲取request對象

    Spring實現(xiàn)在非controller中獲取request對象

    這篇文章主要介紹了Spring實現(xiàn)在非controller中獲取request對象方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Spring Boot自定義Banner實現(xiàn)代碼

    Spring Boot自定義Banner實現(xiàn)代碼

    這篇文章主要介紹了Spring Boot自定義Banner實現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-01-01
  • mybatis-xml映射文件及mybatis動態(tài)sql詳解

    mybatis-xml映射文件及mybatis動態(tài)sql詳解

    XML映射文件的名稱與Mapper接口名稱一致,并且將XML映射文件和Mapper接口放置在相同包下(同包同名),這篇文章主要介紹了mybatis-xml映射文件及mybatis動態(tài)sql的相關(guān)知識,感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • SpringBoot部署在tomcat容器中運(yùn)行的部署方法

    SpringBoot部署在tomcat容器中運(yùn)行的部署方法

    這篇文章主要介紹了SpringBoot部署在tomcat容器中運(yùn)行的部署方法,需要的朋友可以參考下
    2018-10-10
  • Java8 Stream中對集合數(shù)據(jù)進(jìn)行快速匹配和賦值的代碼示例

    Java8 Stream中對集合數(shù)據(jù)進(jìn)行快速匹配和賦值的代碼示例

    這篇文章主要介紹了Java8 Stream中如何對集合數(shù)據(jù)進(jìn)行快速匹配和賦值,文中通過代碼示例為大家介紹的非常詳細(xì),具有一定的參考價值,需要的朋友可以參考下
    2023-06-06
  • Spring七大事務(wù)傳遞機(jī)制深入分析實現(xiàn)原理

    Spring七大事務(wù)傳遞機(jī)制深入分析實現(xiàn)原理

    實際項目開發(fā)中,如果涉及到多張表操作時,為了保證業(yè)務(wù)數(shù)據(jù)的一致性,大家一般都會采用事務(wù)機(jī)制,好多小伙伴可能只是簡單了解一下,遇到事務(wù)失效的情況,便會無從下手,下面這篇文章主要給大家介紹了關(guān)于Spring事務(wù)傳遞機(jī)制的相關(guān)資料,需要的朋友可以參考下
    2023-03-03
  • MybatisPlus搭建項目環(huán)境及分頁插件

    MybatisPlus搭建項目環(huán)境及分頁插件

    Mybatis-Plus(簡稱MP)是一個Mybatis的增強(qiáng)工具,在Mybatis的基礎(chǔ)上只做增強(qiáng)不做改變,為簡化開發(fā)、提高效率而生,下面這篇文章主要給大家介紹了關(guān)于MybatisPlus搭建項目環(huán)境及分頁插件的相關(guān)資料,需要的朋友可以參考下
    2022-11-11

最新評論