最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java中Locks的使用詳解

 更新時(shí)間:2020年03月23日 10:47:47   作者:flydean  
這篇文章主要介紹了java中Locks的使用詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

之前文章中我們講到,java中實(shí)現(xiàn)同步的方式是使用synchronized block。在java 5中,Locks被引入了,來提供更加靈活的同步控制。

本文將會(huì)深入的講解Lock的使用。

Lock和Synchronized Block的區(qū)別

我們?cè)谥暗腟ynchronized Block的文章中講到了使用Synchronized來實(shí)現(xiàn)java的同步。既然Synchronized Block那么好用,為什么會(huì)引入新的Lock呢?

主要有下面幾點(diǎn)區(qū)別:

  • synchronized block只能寫在一個(gè)方法里面,而Lock的lock()和unlock()可以分別在不同的方法里面。
  • synchronized block 不支持公平鎖,一旦鎖被釋放,任何線程都有機(jī)會(huì)獲取被釋放的鎖。而使用 Lock APIs則可以支持公平鎖。從而讓等待時(shí)間最長的線程有限執(zhí)行。
  • 使用synchronized block,如果線程拿不到鎖,將會(huì)被Blocked。 Lock API 提供了一個(gè)tryLock() 的方法,可以判斷是否可以獲得lock,這樣可以減少線程被阻塞的時(shí)間。
  • 當(dāng)線程在等待synchronized block鎖的時(shí)候,是不能被中斷的。如果使用Lock API,則可以使用 lockInterruptibly()來中斷線程。

Lock interface

我們來看下Lock interface的定義, Lock interface定義了下面幾個(gè)主要使用的方法:

  • void lock() - 嘗試獲取鎖,如果獲取不到鎖,則會(huì)進(jìn)入阻塞狀態(tài)。
  • void lockInterruptibly() - 和lock()很類似,但是它可以將正在阻塞的線程中斷,并拋出java.lang.InterruptedException。
  • boolean tryLock() – 這是lock()的非阻塞版本,它回嘗試獲取鎖,并立刻返回是否獲取成功。
  • boolean tryLock(long timeout, TimeUnit timeUnit) – 和tryLock()很像,只是多了一個(gè)嘗試獲取鎖的時(shí)間。
  • void unlock() – unlock實(shí)例。
  • Condition newCondition() - 生成一個(gè)和當(dāng)前Lock實(shí)例綁定的Condition。

在使用Lock的時(shí)候,一定要unlocked,以避免死鎖。所以,通常我們我們要在try catch中使用:

Lock lock = ...; 
lock.lock();
try {
  // access to the shared resource
} finally {
  lock.unlock();
}

除了Lock接口,還有一個(gè)ReadWriteLock接口,在其中定義了兩個(gè)方法,實(shí)現(xiàn)了讀鎖和寫鎖分離:

  • Lock readLock() – 返回讀鎖
  • Lock writeLock() – 返回寫鎖

其中讀鎖可以同時(shí)被很多線程獲得,只要不進(jìn)行寫操作。寫鎖同時(shí)只能被一個(gè)線程獲取。

接下來,我們幾個(gè)Lock的常用是實(shí)現(xiàn)類。

ReentrantLock

ReentrantLock是Lock的一個(gè)實(shí)現(xiàn),什么是ReentrantLock(可重入鎖)呢?

簡單點(diǎn)說可重入鎖就是當(dāng)前線程已經(jīng)獲得了該鎖,如果該線程的其他方法在調(diào)用的時(shí)候也需要獲取該鎖,那么該鎖的lock數(shù)量+1,并且允許進(jìn)入該方法。

不可重入鎖:只判斷這個(gè)鎖有沒有被鎖上,只要被鎖上申請(qǐng)鎖的線程都會(huì)被要求等待。實(shí)現(xiàn)簡單
可重入鎖:不僅判斷鎖有沒有被鎖上,還會(huì)判斷鎖是誰鎖上的,當(dāng)就是自己鎖上的時(shí)候,那么他依舊可以再次訪問臨界資源,并把加鎖次數(shù)加一。

我們看下怎么使用ReentrantLock:

  public void perform() {

    lock.lock();
    try {
      counter++;
    } finally {
      lock.unlock();
    }
  }

下面是使用tryLock()的例子:

  public void performTryLock() throws InterruptedException {
    boolean isLockAcquired = lock.tryLock(1, TimeUnit.SECONDS);

    if(isLockAcquired) {
      try {
        counter++;
      } finally {
        lock.unlock();
      }
    }
  }

ReentrantReadWriteLock

ReentrantReadWriteLock是ReadWriteLock的一個(gè)實(shí)現(xiàn)。上面也講到了ReadWriteLock主要有兩個(gè)方法:

  • Read Lock - 如果沒有線程獲得寫鎖,那么可以多個(gè)線程獲得讀鎖。
  • Write Lock - 如果沒有其他的線程獲得讀鎖和寫鎖,那么只有一個(gè)線程能夠獲得寫鎖。

我們看下怎么使用writeLock:

  Map<String,String> syncHashMap = new HashMap<>();
  ReadWriteLock lock = new ReentrantReadWriteLock();

  Lock writeLock = lock.writeLock();

  public void put(String key, String value) {
    try {
      writeLock.lock();
      syncHashMap.put(key, value);
    } finally {
      writeLock.unlock();
    }
  }

  public String remove(String key){
    try {
      writeLock.lock();
      return syncHashMap.remove(key);
    } finally {
      writeLock.unlock();
    }
  }

再看下怎么使用readLock:

  Lock readLock = lock.readLock();
  public String get(String key){
    try {
      readLock.lock();
      return syncHashMap.get(key);
    } finally {
      readLock.unlock();
    }
  }

  public boolean containsKey(String key) {
    try {
      readLock.lock();
      return syncHashMap.containsKey(key);
    } finally {
      readLock.unlock();
    }
  }

StampedLock

StampedLock也支持讀寫鎖,獲取鎖的是會(huì)返回一個(gè)stamp,通過該stamp來進(jìn)行釋放鎖操作。

上我們講到了如果寫鎖存在的話,讀鎖是無法被獲取的。但有時(shí)候我們讀操作并不想進(jìn)行加鎖操作,這個(gè)時(shí)候我們就需要使用樂觀讀鎖。

StampedLock中的stamped類似樂觀鎖中的版本的概念,當(dāng)我們?cè)?br /> StampedLock中調(diào)用lock方法的時(shí)候,就會(huì)返回一個(gè)stamp,代表鎖當(dāng)時(shí)的狀態(tài),在樂觀讀鎖的使用過程中,在讀取數(shù)據(jù)之后,我們回去判斷該stamp狀態(tài)是否變化,如果變化了就說明該stamp被另外的write線程修改了,這說明我們之前的讀是無效的,這個(gè)時(shí)候我們就需要將樂觀讀鎖升級(jí)為讀鎖,來重新獲取數(shù)據(jù)。

我們舉個(gè)例子,先看下write排它鎖的情況:

  private double x, y;
  private final StampedLock sl = new StampedLock();

  void move(double deltaX, double deltaY) { // an exclusively locked method
    long stamp = sl.writeLock();
    try {
      x += deltaX;
      y += deltaY;
    } finally {
      sl.unlockWrite(stamp);
    }
  }

再看下樂觀讀鎖的情況:

  double distanceFromOrigin() { // A read-only method
    long stamp = sl.tryOptimisticRead();
    double currentX = x, currentY = y;
    if (!sl.validate(stamp)) {
      stamp = sl.readLock();
      try {
        currentX = x;
        currentY = y;
      } finally {
        sl.unlockRead(stamp);
      }
    }
    return Math.sqrt(currentX * currentX + currentY * currentY);
  }

上面使用tryOptimisticRead()來嘗試獲取樂觀讀鎖,然后通過sl.validate(stamp)來判斷該stamp是否被改變,如果改變了,說明之前的read是無效的,那么需要重新來讀取。

最后,StampedLock還提供了一個(gè)將read鎖和樂觀讀鎖升級(jí)為write鎖的功能:

  void moveIfAtOrigin(double newX, double newY) { // upgrade
    // Could instead start with optimistic, not read mode
    long stamp = sl.readLock();
    try {
      while (x == 0.0 && y == 0.0) {
        long ws = sl.tryConvertToWriteLock(stamp);
        if (ws != 0L) {
          stamp = ws;
          x = newX;
          y = newY;
          break;
        }
        else {
          sl.unlockRead(stamp);
          stamp = sl.writeLock();
        }
      }
    } finally {
      sl.unlock(stamp);
    }
  }

上面的例子是通過使用tryConvertToWriteLock(stamp)來實(shí)現(xiàn)升級(jí)的。

Conditions

上面講Lock接口的時(shí)候有提到其中的一個(gè)方法:

Condition newCondition();

Condition提供了await和signal方法,類似于Object中的wait和notify。

不同的是Condition提供了更加細(xì)粒度的等待集劃分。我們舉個(gè)例子:

public class ConditionUsage {
  final Lock lock = new ReentrantLock();
  final Condition notFull = lock.newCondition();
  final Condition notEmpty = lock.newCondition();

  final Object[] items = new Object[100];
  int putptr, takeptr, count;

  public void put(Object x) throws InterruptedException {
    lock.lock();
    try {
      while (count == items.length)
        notFull.await();
      items[putptr] = x;
      if (++putptr == items.length) putptr = 0;
      ++count;
      notEmpty.signal();
    } finally {
      lock.unlock();
    }
  }

  public Object take() throws InterruptedException {
    lock.lock();
    try {
      while (count == 0)
        notEmpty.await();
      Object x = items[takeptr];
      if (++takeptr == items.length) takeptr = 0;
      --count;
      notFull.signal();
      return x;
    } finally {
      lock.unlock();
    }
  }
}

上面的例子實(shí)現(xiàn)了一個(gè)ArrayBlockingQueue,我們可以看到在同一個(gè)Lock實(shí)例中,創(chuàng)建了兩個(gè)Condition,分別代表隊(duì)列未滿,隊(duì)列未空。通過這種細(xì)粒度的劃分,我們可以更好的控制業(yè)務(wù)邏輯。

本文的例子可以參考https://github.com/ddean2009/learn-java-concurrency/tree/master/Locks

到此這篇關(guān)于java中Locks的使用詳解的文章就介紹到這了,更多相關(guān)java Locks內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java中for循環(huán)刪除集合陷阱

    java中for循環(huán)刪除集合陷阱

    java中在增強(qiáng)for循環(huán)為什么不能增刪集合呢?一個(gè)循環(huán)迭代,跟集合的增刪改沒什么關(guān)系。修改集合不是for去做的。for只管循環(huán)迭代,你在循環(huán)里邊修改集合,改變集合的長度,順序?qū)ρh(huán)都有影響
    2015-05-05
  • Java中間消息件ActiveMQ使用實(shí)例

    Java中間消息件ActiveMQ使用實(shí)例

    這篇文章主要介紹了Java中間消息件ActiveMQ使用實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • RocketMQ?Namesrv架構(gòu)工作原理詳解

    RocketMQ?Namesrv架構(gòu)工作原理詳解

    這篇文章主要為大家介紹了RocketMQ?Namesrv架構(gòu)工作原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • SpringBoot Redis配置多數(shù)據(jù)源的項(xiàng)目實(shí)踐

    SpringBoot Redis配置多數(shù)據(jù)源的項(xiàng)目實(shí)踐

    springboot中默認(rèn)的redis配置是只能對(duì)單個(gè)redis庫進(jìn)行操作的, 那么我們需要多個(gè)庫操作的時(shí)候這個(gè)時(shí)候就可以采用redis多數(shù)據(jù)源 ,本文就介紹了SpringBoot Redis配置多數(shù)據(jù)源,感興趣的可以了解一下
    2023-07-07
  • RocketMQ重試機(jī)制及消息冪代碼實(shí)例解析

    RocketMQ重試機(jī)制及消息冪代碼實(shí)例解析

    這篇文章主要介紹了RocketMQ重試機(jī)制及消息冪代碼實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • 用Java打印九九除法表代碼分析

    用Java打印九九除法表代碼分析

    這篇文章主要介紹了如何用Java語言打印九九除法表,包括其使用的源代碼,需要的朋友可以參考下。
    2017-08-08
  • Java中-Xms和-Xmx參數(shù)的使用與默認(rèn)內(nèi)存設(shè)置

    Java中-Xms和-Xmx參數(shù)的使用與默認(rèn)內(nèi)存設(shè)置

    在 Java 程序運(yùn)行時(shí),內(nèi)存的管理是影響程序性能的關(guān)鍵因素之一,Java 程序使用的內(nèi)存主要由兩部分組成:堆內(nèi)存和棧內(nèi)存,Java 提供了多個(gè)參數(shù)來控制堆內(nèi)存的大小,其中最常用的參數(shù)是 -Xms 和 -Xmx,本文將詳細(xì)介紹這些參數(shù),需要的朋友可以參考下
    2024-11-11
  • 在Action中以Struts2的方式輸出JSON數(shù)據(jù)的實(shí)例

    在Action中以Struts2的方式輸出JSON數(shù)據(jù)的實(shí)例

    下面小編就為大家?guī)硪黄贏ction中以Struts2的方式輸出JSON數(shù)據(jù)的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-11-11
  • Elasticsearch聚合查詢概念及字段類型示例

    Elasticsearch聚合查詢概念及字段類型示例

    這篇文章主要為大家介紹了Elasticsearch聚合查詢概念及字段類型示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • 工廠模式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    工廠模式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要介紹了工廠模式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理的相關(guān)資料,需要的朋友可以參考下
    2017-08-08

最新評(píng)論

呼和浩特市| 亳州市| 和平区| 墨竹工卡县| 长寿区| 南昌市| 铁岭市| 旌德县| 兰考县| 东兰县| 湘阴县| 乐业县| 绍兴县| 马鞍山市| 上杭县| 安吉县| 黎川县| 遂溪县| 杭锦旗| 河津市| 聂拉木县| 寿光市| 昌江| 赤水市| 常州市| 关岭| 武川县| 青川县| 绩溪县| 府谷县| 滁州市| 曲麻莱县| 岑溪市| 台安县| 大悟县| 西城区| 平原县| 博白县| 定西市| 青龙| 通化市|