91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

String中怎么實現一個同步鎖

發布時間:2021-08-06 17:19:25 來源:億速云 閱讀:119 作者:Leah 欄目:編程語言

String中怎么實現一個同步鎖,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

在某些時候,我們可能想基于字符串做一些事情,比如:針對同一用戶的并發同步操作,使用鎖字符串的方式實現比較合理。因為只有在相同字符串的情況下,并發操作才是不被允許的。而如果我們不分青紅皂白直接全部加鎖,那么整體性能就下降得厲害了。

因為string的多樣性,看起來string鎖是天然比分段鎖之類的高級鎖更有優勢呢。

因為String 類型的變量賦值是這樣的: String a = "hello world."; 所有往往會有個錯誤的映象,String對象就是不可變的。

額,關于這個問題的爭論咱們就不細說了,總之, "a" != "a" 是有可能成立的。

另外,針對上鎖這件事,我們都知道,鎖是要針對同一個對象,才會有意義。所以,粗略的,我們可以這樣使用字符串鎖:

public void method1() {    String str1 = "a";    synchronized (str1) {      // do sync a things...    }  }      public void method2() {    String str2 = "a";    synchronized (str2) {      // do sync b things...    }  }

乍一看,這的確很方便簡單。但是,前面說了, "a" 是可能不等于 "a" 的(這是大部分情況,只有當String被存儲在常量池中時值相同的String變量才相等)。

所以,我們可以稍微優化下:

public void method3() {    String str1 = "a";    synchronized (str1.intern()) {      // do sync a things...    }  }  public void method4() {    String str2 = "a";    synchronized (str2.intern()) {      // do sync b things...    }  }

看起來還是很方便簡單的,其原理就是把String對象放到常量池中。但是會有個問題,這些常量池的數據如何清理呢?

不管怎么樣,我們是不是可以自己去基于String實現一個鎖呢?

肯定是可以的了!直接上代碼!

import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ConcurrentMap;import java.util.concurrent.CountDownLatch;/** * 基于string 的鎖實現 */public final class StringBasedMutexLock {  private static final Logger logger = LoggerFactory.getLogger(StringBasedMutexLock.class);  /**   * 字符鎖 管理器, 將每個字符串 轉換為一個 CountDownLatch   *   *   即鎖只會發生在真正有并發更新 同一個 String 的情況下   *   */  private static final ConcurrentMap<String, CountDownLatch> lockKeyHolder = new ConcurrentHashMap<>();  /**   * 基于lockKey 上鎖,同步執行   *   * @param lockKey 字符鎖   */  public static void lock(String lockKey) {    while (!tryLock(lockKey)) {      try {        logger.debug("【字符鎖】并發更新鎖升級, {}", lockKey);        blockOnSecondLevelLock(lockKey);      } catch (InterruptedException e) {        Thread.currentThread().interrupt();        logger.error("【字符鎖】中斷異常:" + lockKey, e);        break;      }    }  }  /**   * 釋放 lockKey 對應的鎖選項,使其他線程可執行   *   * @param lockKey 要使用互斥的字符串   * @return true: 釋放成功, false: 釋放失敗,可能被其他線程誤釋放   */  public static boolean unlock(String lockKey) {    // 先刪除鎖,再釋放鎖,此處會導致后續進來的并發優先執行,無影響    CountDownLatch realLock = getAndReleaseLock1(lockKey);    releaseSecondLevelLock(realLock);    return true;  }  /**   * 嘗試給指定字符串上鎖   *   * @param lockKey 要使用互斥的字符串   * @return true: 上鎖成功, false: 上鎖失敗   */  private static boolean tryLock(String lockKey) {    // 此處會導致大量 ReentrantLock 對象創建嗎?    // 其實不會的,這個數量最大等于外部并發數,只是對 gc 不太友好,會反復創建反復銷毀y    return lockKeyHolder.putIfAbsent(lockKey, new CountDownLatch(1)) == null;  }  /**   * 釋放1級鎖(刪除) 并返回重量級鎖   *   * @param lockKey 字符鎖   * @return 真正的鎖   */  private static CountDownLatch getAndReleaseLock1(String lockKey) {    return lockKeyHolder.remove(lockKey);  }  /**   * 二級鎖鎖定(鎖升級)   *   * @param lockKey 鎖字符串   * @throws InterruptedException 中斷時拋出異常   */  private static void blockOnSecondLevelLock(String lockKey) throws InterruptedException {    CountDownLatch realLock = getRealLockByKey(lockKey);    // 為 null 說明此時鎖已被刪除, next race    if(realLock != null) {      realLock.await();    }  }  /**   * 二級鎖解鎖(如有必要)   *   * @param realLock 鎖實例   */  private static void releaseSecondLevelLock(CountDownLatch realLock) {    realLock.countDown();  }  /**   * 通過key 獲取對應的鎖實例   *   * @param lockKey 字符串鎖   * @return 鎖實例   */  private static CountDownLatch getRealLockByKey(String lockKey) {    return lockKeyHolder.get(lockKey);  }}

使用時,只需傳入 lockKey 即可。

// 加鎖StringBasedMutexLock.lock(linkKey);// 解鎖StringBasedMutexLock.unlock(linkKey);

這樣做有什么好處嗎?

  1. 使用ConcurrentHashMap實現鎖獲取,性能還是不錯的;

  2. 每個字符串對應一個鎖,使用完成后就刪除,不會導致內存溢出問題;

  3. 可以作為一個外部工具使用,業務代碼接入方便,無需像 synchronized 一樣,需要整段代碼包裹起來;

  不足之處?

  1. 使用ConcurrentHashMap實現鎖獲取,性能還是不錯的;

  2. 每個字符串對應一個鎖,使用完成后就刪除,不會導致內存溢出問題;

  3. 可以作為一個外部工具使用,業務代碼接入方便,無需像 synchronized 一樣,需要整段代碼包裹起來;

  4. 本文只是想展示實現 String 鎖,此鎖并不適用于分布式場景下的并發處理;

擴展: 如果不使用 String 做鎖,如何保證大并發前提下的小概率并發場景的線程安全?

我們知道 CAS 的效率是比較高的,我們可以使用原子類來進行CAS的操作。

比如,我們添加一狀態字段, 操作此字段以保證線程安全:

/**   * 運行狀態   *   *     4: 正在刪除, 1: 正在放入隊列中, 0: 正常無運行   */  private transient volatile AtomicInteger runningStatus = new AtomicInteger(0);      // 更新時先獲取該狀態:  public void method5() {    AtomicInteger runningStatus = link.getRunningStatus();    // 正在刪除數據過程中,則等待    if(!runningStatus.compareAndSet(0, 1)) {      // 1. 等待另外線程刪除完成      // 2. 刪除正在更新標識      // 3. 重新運行本次數據放入邏輯      long lockStartTime = System.currentTimeMillis();      long maxLockTime = 10 * 1000;      while (!runningStatus.compareAndSet(0, 1)) {        if(System.currentTimeMillis() - lockStartTime > maxLockTime) {          break;        }      }      runningStatus.compareAndSet(1, 0);      throw new RuntimeException("數據正在更新,重新運行: " + link.getLinkKey() + link);    }    try {      // do sync things    }    finally {      runningStatus.compareAndSet(1, 0);    }  }    public void method6() {    AtomicInteger runningStatus = link.getRunningStatus();    if (!runningStatus.compareAndSet(0, 4)) {      logger.error(" 數據正在更新中,不得刪除,返回 ");      return;    }    try {      // do sync things    }    catch (Exception e) {      logger.error("并發更新異常:", e);    }    finally {      runningStatus.compareAndSet(4, 0);    }  }

實際測試下來,CAS 性能是要比 synchronized 之類的鎖性能要好的。當然,我們這里針對的并發數都是極少的,我們只是想要保證這極少情況下的線程安全性。所以,其實也還好。

關于String中怎么實現一個同步鎖問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

灵山县| 贵阳市| 新和县| 鄄城县| 上犹县| 恩施市| 贵南县| 镇远县| 津南区| 沭阳县| 华蓥市| 衡水市| 庆安县| 南城县| 监利县| 大竹县| 腾冲县| 文山县| 江油市| 淅川县| 连平县| 崇阳县| 上蔡县| 十堰市| 宁海县| 余姚市| 博客| 资中县| 信阳市| 奉贤区| 巴里| 兰考县| 图木舒克市| 贵德县| 浙江省| 镇雄县| 新民市| 砚山县| 高台县| 承德县| 抚顺县|