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

基于String實現(xiàn)同步鎖的方法步驟

 更新時間:2019年09月24日 08:36:36   作者:等你歸去來  
這篇文章主要給大家介紹了關(guān)于基于String實現(xiàn)同步鎖的方法步驟,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用String具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

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

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

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

額,關(guān)于這個問題的爭論咱們就不細說了,總之, "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" 的(這是大部分情況,只有當(dāng)String被存儲在常量池中時值相同的String變量才相等)。

所以,我們可以稍微優(yōu)化下:

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對象放到常量池中。但是會有個問題,這些常量池的數(shù)據(jù)如何清理呢?

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

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;

/**
 * 基于string 的鎖實現(xiàn)
 */
public final class StringBasedMutexLock {

 private static final Logger logger = LoggerFactory.getLogger(StringBasedMutexLock.class);

 /**
  * 字符鎖 管理器, 將每個字符串 轉(zhuǎn)換為一個 CountDownLatch
  *
  *  即鎖只會發(fā)生在真正有并發(fā)更新 同一個 String 的情況下
  *
  */
 private static final ConcurrentMap<String, CountDownLatch> lockKeyHolder = new ConcurrentHashMap<>();

 /**
  * 基于lockKey 上鎖,同步執(zhí)行
  *
  * @param lockKey 字符鎖
  */
 public static void lock(String lockKey) {
  while (!tryLock(lockKey)) {
   try {
    logger.debug("【字符鎖】并發(fā)更新鎖升級, {}", lockKey);
    blockOnSecondLevelLock(lockKey);
   } catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    logger.error("【字符鎖】中斷異常:" + lockKey, e);
    break;
   }
  }
 }

 /**
  * 釋放 lockKey 對應(yīng)的鎖選項,使其他線程可執(zhí)行
  *
  * @param lockKey 要使用互斥的字符串
  * @return true: 釋放成功, false: 釋放失敗,可能被其他線程誤釋放
  */
 public static boolean unlock(String lockKey) {
  // 先刪除鎖,再釋放鎖,此處會導(dǎo)致后續(xù)進來的并發(fā)優(yōu)先執(zhí)行,無影響
  CountDownLatch realLock = getAndReleaseLock1(lockKey);
  releaseSecondLevelLock(realLock);
  return true;
 }

 /**
  * 嘗試給指定字符串上鎖
  *
  * @param lockKey 要使用互斥的字符串
  * @return true: 上鎖成功, false: 上鎖失敗
  */
 private static boolean tryLock(String lockKey) {
  // 此處會導(dǎo)致大量 ReentrantLock 對象創(chuàng)建嗎?
  // 其實不會的,這個數(shù)量最大等于外部并發(fā)數(shù),只是對 gc 不太友好,會反復(fù)創(chuàng)建反復(fù)銷毀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 獲取對應(yīng)的鎖實例
  *
  * @param lockKey 字符串鎖
  * @return 鎖實例
  */
 private static CountDownLatch getRealLockByKey(String lockKey) {
  return lockKeyHolder.get(lockKey);
 }

}

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

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

這樣做有什么好處嗎?

  1. 使用ConcurrentHashMap實現(xiàn)鎖獲取,性能還是不錯的;

  2. 每個字符串對應(yīng)一個鎖,使用完成后就刪除,不會導(dǎo)致內(nèi)存溢出問題;

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

  不足之處?

  1. 使用ConcurrentHashMap實現(xiàn)鎖獲取,性能還是不錯的;

  2. 每個字符串對應(yīng)一個鎖,使用完成后就刪除,不會導(dǎo)致內(nèi)存溢出問題;

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

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

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

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

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

/**
  * 運行狀態(tài)
  *
  *   4: 正在刪除, 1: 正在放入隊列中, 0: 正常無運行
  */
 private transient volatile AtomicInteger runningStatus = new AtomicInteger(0);
 
 
 // 更新時先獲取該狀態(tài):
 public void method5() {
  AtomicInteger runningStatus = link.getRunningStatus();
  // 正在刪除數(shù)據(jù)過程中,則等待
  if(!runningStatus.compareAndSet(0, 1)) {
   // 1. 等待另外線程刪除完成
   // 2. 刪除正在更新標(biāo)識
   // 3. 重新運行本次數(shù)據(jù)放入邏輯
   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("數(shù)據(jù)正在更新,重新運行: " + 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(" 數(shù)據(jù)正在更新中,不得刪除,返回 ");
   return;
  }
  try {
   // do sync things
  }
  catch (Exception e) {
   logger.error("并發(fā)更新異常:", e);
  }
  finally {
   runningStatus.compareAndSet(4, 0);
  }
 }

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

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。

相關(guān)文章

  • Java?List集合取交集的8種不同實現(xiàn)方式總結(jié)

    Java?List集合取交集的8種不同實現(xiàn)方式總結(jié)

    工作中經(jīng)常遇到需要取兩個集合之間的交集、差集情況,下面這篇文章主要給大家總結(jié)介紹了關(guān)于Java?List集合取交集的8種不同實現(xiàn)方式,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-04-04
  • java使用反射給對象屬性賦值的兩種方法

    java使用反射給對象屬性賦值的兩種方法

    JAVA反射機制是在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法,下面這篇文章主要給大家介紹了關(guān)于java使用反射給對象屬性賦值的兩種方法,需要的朋友可以參考下
    2023-04-04
  • 使用Java實現(xiàn)MapReduce詞頻統(tǒng)計示例代碼

    使用Java實現(xiàn)MapReduce詞頻統(tǒng)計示例代碼

    這篇文章主要介紹了使用Java實現(xiàn)MapReduce詞頻統(tǒng)計的相關(guān)資料,通過詞頻統(tǒng)計示例來展示MapReduce的運行機制,涵蓋了Mapper和Reducer的實現(xiàn),并說明了如何配置和執(zhí)行MapReduce作業(yè),需要的朋友可以參考下
    2024-11-11
  • Java利用Guava?Retry實現(xiàn)重處理

    Java利用Guava?Retry實現(xiàn)重處理

    guava-retrying是谷歌的Guava庫的一個小擴展,允許為任意函數(shù)調(diào)用創(chuàng)建可配置的重試策略,比如與正常運行時間不穩(wěn)定的遠程服務(wù)對話的函數(shù)調(diào)用。本文將利用其實現(xiàn)重處理,感興趣的可以了解一下
    2022-08-08
  • SpringBoot添加SSL證書的方法

    SpringBoot添加SSL證書的方法

    HTTPS 實際上就是 HTTP + SSL,使我們的網(wǎng)站更加安全,地址欄上會有一把小鎖。那么如何在SpringBoot添加SSL證書,下面就一起來了解一下
    2021-05-05
  • java如何實現(xiàn)判斷文件的真實類型

    java如何實現(xiàn)判斷文件的真實類型

    本篇文章主要介紹了java如何實現(xiàn)判斷文件的真實類型,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • Java?Valhalla?Project項目介紹

    Java?Valhalla?Project項目介紹

    這篇文章主要介紹了Java?Valhalla?Project項目介紹,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09
  • 詳解Maven項目缺少Maven Dependencies解決方法總結(jié)

    詳解Maven項目缺少Maven Dependencies解決方法總結(jié)

    這篇文章主要介紹了詳解Maven項目缺少Maven Dependencies解決方法總結(jié),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Java代理模式的深入了解

    Java代理模式的深入了解

    這篇文章主要為大家介紹了Java代理模式,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • Java 使用IO流實現(xiàn)大文件的分割與合并實例詳解

    Java 使用IO流實現(xiàn)大文件的分割與合并實例詳解

    這篇文章主要介紹了Java 使用IO流實現(xiàn)大文件的分割與合并實例詳解的相關(guān)資料,需要的朋友可以參考下
    2016-12-12

最新評論

历史| 荔波县| 甘南县| 清流县| 松阳县| 托克托县| 开封市| 湘阴县| 瑞昌市| 凉城县| 娄底市| 怀远县| 盐山县| 微博| 息烽县| 泸西县| 南雄市| 柘城县| 明光市| 霍林郭勒市| 仪征市| 新竹市| 广南县| 无棣县| 同德县| 合川市| 疏附县| 屯昌县| 江都市| 宁明县| 禄劝| 竹北市| 张家港市| 宜兰县| 灯塔市| 巴东县| 伽师县| 宣武区| 建昌县| 宁都县| 民权县|