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

解決線程并發(fā)redisson使用遇到的坑

 更新時(shí)間:2021年06月18日 11:16:15   作者:KingdomCoder  
這篇文章主要介紹了解決線程并發(fā)redisson使用遇到的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

線程并發(fā)redisson的坑

背景

因?yàn)闃I(yè)務(wù)上的一個(gè)購買需求,需要對(duì)庫存進(jìn)行行程保護(hù),防止超賣的出現(xiàn)(我們不是電商公司),經(jīng)過調(diào)研,最終選擇使用Redission來進(jìn)行控制。

主要因?yàn)镽edission豐富的API,開源框架,已經(jīng)被廣泛應(yīng)用于實(shí)際生產(chǎn)環(huán)境。

問題描述

當(dāng)我們使用Ression中Lock.lock()方法之后,如果存在線程并發(fā)常見情況下,會(huì)出現(xiàn)如下異常:

java.lang.IllegalMonitorStateException: attempt to unlock lock, not locked by current thread by node id: 9f178836-f7e1-44fe-a89d-2db52f399c0d thread-id: 22

問題分析

在thread-1還沒有結(jié)束的時(shí)候,也就是在thread-1在獲得鎖但是還沒有釋放鎖的時(shí)候, `thread-2由于被別的線程中斷停止了等待從lock.tryLock的阻塞狀態(tài)中返回繼續(xù)執(zhí)行接下來的邏輯,并且由于嘗試去釋放一個(gè)屬于線程thread-1的鎖而拋出了一個(gè)運(yùn)行時(shí)異常導(dǎo)致該線程thread-2結(jié)束了, 然而thread-2完成了一系列操作后,線程thread-1才釋放了自己的鎖.

所以thread-2并沒有獲得鎖,卻執(zhí)行了需要同步的內(nèi)容,還嘗試去釋放鎖。

那解決方式我們就知道了,當(dāng)前線程加的鎖由當(dāng)前線程去解鎖,也就是說當(dāng)我們使用lock.unlock的時(shí)候加上線程的判斷即可。

問題解決

 RLock lock = redissonClient.getLock(key);
    if(lock.isLocked()){ // 是否還是鎖定狀態(tài)
      if(lock.isHeldByCurrentThread()){ // 時(shí)候是當(dāng)前執(zhí)行線程的鎖
        lock.unlock(); // 釋放鎖
      }
    }

redisson使用注意事項(xiàng)

Redisson 是一個(gè)在 Redis 的基礎(chǔ)上實(shí)現(xiàn)的 Java 駐內(nèi)存數(shù)據(jù)網(wǎng)格,相較于暴露底層操作的Jedis,Redisson提供了一系列的分布式的 Java 常用對(duì)象,還提供了許多分布式服務(wù)。

特性 & 功能:

  • 支持 Redis 單節(jié)點(diǎn)(single)模式、哨兵(sentinel)模式、主從(Master/Slave)模式以及集群(Redis Cluster)模式
  • 程序接口調(diào)用方式采用異步執(zhí)行和異步流執(zhí)行兩種方式
  • 數(shù)據(jù)序列化,Redisson 的對(duì)象編碼類是用于將對(duì)象進(jìn)行序列化和反序列化,以實(shí)現(xiàn)對(duì)該對(duì)象在 Redis 里的讀取和存儲(chǔ)
  • 單個(gè)集合數(shù)據(jù)分片,在集群模式下,Redisson 為單個(gè) Redis 集合類型提供了自動(dòng)分片的功能
  • 提供多種分布式對(duì)象,如:Object Bucket,Bitset,AtomicLong,Bloom Filter 和 HyperLogLog 等
  • 提供豐富的分布式集合,如:Map,Multimap,Set,SortedSet,List,Deque,Queue 等
  • 分布式鎖和同步器的實(shí)現(xiàn),可重入鎖(Reentrant Lock),公平鎖(Fair Lock),聯(lián)鎖(MultiLock),紅鎖(Red Lock),信號(hào)量(Semaphonre),可過期性信號(hào)鎖(PermitExpirableSemaphore)等
  • 提供先進(jìn)的分布式服務(wù),如分布式遠(yuǎn)程服務(wù)(Remote Service),分布式實(shí)時(shí)對(duì)象(Live Object)服務(wù),分布式執(zhí)行服務(wù)(Executor Service),分布式調(diào)度任務(wù)服務(wù)(Schedule Service)和分布式映射歸納服務(wù)(MapReduce)
  • 更多特性和功能,請(qǐng)關(guān)注官網(wǎng):http://redisson.org

實(shí)現(xiàn)原理

redis本身是不支持上述的分布式對(duì)象和集合,Redisson是通過利用redis的特性在客戶端實(shí)現(xiàn)了高級(jí)數(shù)據(jù)結(jié)構(gòu)和特性,例如優(yōu)先隊(duì)列的實(shí)現(xiàn),是通過客戶端排序整理后再存入redis。

客戶端實(shí)現(xiàn),意味著當(dāng)沒有任何客戶端在線時(shí),這些所有的數(shù)據(jù)結(jié)構(gòu)和特性都不會(huì)保留,也不會(huì)自動(dòng)生效,例如過期事件的觸發(fā)或原來優(yōu)先隊(duì)列的元素增加。

注意事項(xiàng)

實(shí)時(shí)性

RMap中有一個(gè)功能是可以設(shè)置鍵值對(duì)的過期時(shí)間的,并可以注冊(cè)鍵值對(duì)的事件監(jiān)聽器

元素淘汰功能(Eviction)

Redisson的分布式的RMapCache Java對(duì)象在基于RMap的前提下實(shí)現(xiàn)了針對(duì)單個(gè)元素的淘汰機(jī)制。同時(shí)仍然保留了元素的插入順序。由于RMapCache是基于RMap實(shí)現(xiàn)的,使它同時(shí)繼承了java.util.concurrent.ConcurrentMap接口和java.util.Map接口。Redisson提供的Spring Cache整合以及JCache正是基于這樣的功能來實(shí)現(xiàn)的。

目前的Redis自身并不支持散列(Hash)當(dāng)中的元素淘汰,因此所有過期元素都是通過org.redisson.EvictionScheduler實(shí)例來實(shí)現(xiàn)定期清理的。為了保證資源的有效利用,每次運(yùn)行最多清理300個(gè)過期元素。任務(wù)的啟動(dòng)時(shí)間將根據(jù)上次實(shí)際清理數(shù)量自動(dòng)調(diào)整,間隔時(shí)間趨于1秒到1小時(shí)之間。比如該次清理時(shí)刪除了300條元素,那么下次執(zhí)行清理的時(shí)間將在1秒以后(最小間隔時(shí)間)。一旦該次清理數(shù)量少于上次清理數(shù)量,時(shí)間間隔將增加1.5倍。

正如官方wiki所述,這個(gè)功能是通過后臺(tái)線程定時(shí)去清理的, 所以這個(gè)是非實(shí)時(shí)的(issue-1234:on expired event is not executed in real-time.),延遲在5秒到2小時(shí)之間,因此對(duì)實(shí)時(shí)性要求比較高的場(chǎng)景就得自己衡量了。

由于過期時(shí)間的非實(shí)時(shí)性,所以導(dǎo)致過期事件的發(fā)生也是非實(shí)時(shí)的,相應(yīng)的監(jiān)聽器可能會(huì)延遲了一會(huì)兒才收到通知,在我的測(cè)試中,ttl設(shè)置在秒級(jí)誤差是比較大的,分鐘級(jí)別的ttl倒還好(左側(cè)設(shè)置值,右側(cè)實(shí)際耗時(shí)):

1s _ 5s
3s _ 5s
4s _ 5s
5s _ 9s
6s _ 10s
10s _ 15s
1m _ 1m11s

序列化

由Redisson默認(rèn)的編碼器為JsonJacksonCodec,JsonJackson在序列化有雙向引用的對(duì)象時(shí),會(huì)出現(xiàn)無限循環(huán)異常。而fastjson在檢查出雙向引用后會(huì)自動(dòng)用引用符$ref替換,終止循環(huán)。

在我的情況中,我序列化了一個(gè)service,這個(gè)service已被spring托管,而且和另一個(gè)service之間也相互注入了,用fastjson能 正常序列化到redis,而JsonJackson則拋出無限循環(huán)異常。

為了序列化后的內(nèi)容可見,所以不用redission其他自帶的二進(jìn)制編碼器,自行實(shí)現(xiàn)編碼器:

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import org.redisson.client.codec.BaseCodec;
import org.redisson.client.protocol.Decoder;
import org.redisson.client.protocol.Encoder;​
import java.io.IOException;​
public class FastjsonCodec extends BaseCodec {​
 private final Encoder encoder = in -> {
 ByteBuf out = ByteBufAllocator.DEFAULT.buffer();
 try {
 ByteBufOutputStream os = new ByteBufOutputStream(out);
 JSON.writeJSONString(os, in,SerializerFeature.WriteClassName);
 return os.buffer();
 } catch (IOException e) {
 out.release();
 throw e;
 } catch (Exception e) {
 out.release();
 throw new IOException(e);
 }
 };
​
 private final Decoder<Object> decoder = (buf, state) ->
 JSON.parseObject(new ByteBufInputStream(buf), Object.class);
​
 @Override
 public Decoder<Object> getValueDecoder() {
 return decoder;
 }
​
 @Override
 public Encoder getValueEncoder() {
 return encoder;
 }
}

訂閱發(fā)布

Redisson對(duì)訂閱發(fā)布的封裝是RTopic,這也是Redisson中很多事件監(jiān)聽的實(shí)現(xiàn)原理(例如鍵值對(duì)的事件監(jiān)聽)。

使用單元測(cè)試時(shí)發(fā)現(xiàn),在事件發(fā)布后,訂閱方需要延時(shí)一下才能收到事件。具體原因待查。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring中@Async的使用小結(jié)

    Spring中@Async的使用小結(jié)

    在Java開發(fā)中,我們常常會(huì)遇到需要執(zhí)行耗時(shí)操作的場(chǎng)景,例如文件上傳、網(wǎng)絡(luò)請(qǐng)求等,本文將介紹如何在Java中使用異步方法,并探討其中的一些注意事項(xiàng),感興趣的朋友跟隨小編一起看看吧
    2024-01-01
  • Java集合教程之Collection實(shí)例詳解

    Java集合教程之Collection實(shí)例詳解

    集合,或者叫容器,是一個(gè)包含多個(gè)元素的對(duì)象,下面這篇文章主要給大家介紹了關(guān)于Java集合教程之Collection的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-08-08
  • Java終止線程的兩種方法

    Java終止線程的兩種方法

    本文主要介紹了Java終止線程的兩種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • java之super關(guān)鍵字用法實(shí)例解析

    java之super關(guān)鍵字用法實(shí)例解析

    這篇文章主要介紹了java之super關(guān)鍵字用法實(shí)例解析,較為詳細(xì)的分析了super關(guān)鍵字的用法及內(nèi)存分布,需要的朋友可以參考下
    2014-09-09
  • Java正則提取中括號(hào)中的內(nèi)容操作示例

    Java正則提取中括號(hào)中的內(nèi)容操作示例

    這篇文章主要介紹了Java正則提取中括號(hào)中的內(nèi)容操作,涉及Java針對(duì)字符串的正則匹配、轉(zhuǎn)換、遍歷等相關(guān)操作技巧,需要的朋友可以參考下
    2018-06-06
  • java如何判斷Date是上午還是下午

    java如何判斷Date是上午還是下午

    文章介紹了三種在Java中判斷Date對(duì)象是上午還是下午的方法:使用Calendar類、使用Java 8的java.time包以及使用SimpleDateFormat進(jìn)行格式化輸出,每種方法都有代碼示例和解釋,幫助開發(fā)者根據(jù)具體需求選擇合適的方法
    2025-03-03
  • 基于@AllArgsConstructor與@Value共用的問題解決

    基于@AllArgsConstructor與@Value共用的問題解決

    這篇文章主要介紹了基于@AllArgsConstructor與@Value共用的問題解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 單點(diǎn)登錄的概念及SpringBoot實(shí)現(xiàn)單點(diǎn)登錄的操作方法

    單點(diǎn)登錄的概念及SpringBoot實(shí)現(xiàn)單點(diǎn)登錄的操作方法

    在本文中,我們將使用Spring Boot構(gòu)建一個(gè)基本的單點(diǎn)登錄系統(tǒng),我們將介紹如何使用Spring Security和JSON Web Tokens(JWTs)來實(shí)現(xiàn)單點(diǎn)登錄功能,本文假設(shè)您已經(jīng)熟悉Spring Boot和Spring Security,感興趣的朋友一起看看吧
    2024-10-10
  • 解析Java格式字符串的使用

    解析Java格式字符串的使用

    本文通過實(shí)例給大家介紹了java格式字符串的使用,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2022-02-02
  • Java使用正則表達(dá)式判斷獨(dú)立字符的存在(代碼示例)

    Java使用正則表達(dá)式判斷獨(dú)立字符的存在(代碼示例)

    通過使用正則表達(dá)式,我們可以更加靈活地判斷字符串中是否包含特定的字符,并且可以控制匹配的條件,如獨(dú)立的字符,這為我們處理字符串提供了更多的選擇和功能,這篇文章主要介紹了Java使用正則表達(dá)式判斷獨(dú)立字符的存在,需要的朋友可以參考下
    2023-10-10

最新評(píng)論

三明市| 丹棱县| 蓬安县| 乐都县| 崇左市| 廊坊市| 正蓝旗| 江达县| 邛崃市| 西藏| 新野县| 大名县| 陇川县| 汉阴县| 蒲城县| 周口市| 永平县| 昌吉市| 彰化县| 芒康县| 宝丰县| 利川市| 赫章县| 玉龙| 张家口市| 岢岚县| 达孜县| 文安县| 扶风县| 屏东市| 景谷| 个旧市| 湄潭县| 阜新| 南川市| 盐津县| 南岸区| 麻城市| 高雄县| 江津市| 新晃|