Redisson分佈式鎖的簡單使用

作一個積極的人html

編碼、改bug、提高本身java

我有一個樂園,面向編程,春暖花開!git

=================================================github

對人工智能感興趣的夥伴,分享一個我朋友的人工智能教程。零基礎!通俗易懂!風趣幽默!你們能夠看看是否對本身有幫助,點擊這裏查看教程redis

=================================================數據庫

一:前言

我在實際環境中遇到了這樣一種問題,分佈式生成id的問題!由於業務邏輯的問題,我有個生成id的方法,是根據業務標識+id 當作惟一的值! 而uuid是遞增生成的,從1開始一直遞增,那麼在同一臺機器上運行代碼,加上同步方法(synchronized),這個生成id的方法就是ok!編程

可是由於業務擴展或者說爲了安全,項目運行在兩臺機器上,此時單個的同步方法(synchronized或者Lock)就不能防止id的重複了!!!安全


要解決上面的這個問題,其餘有以下解決辦法! (1):每臺機器生產Id的代碼,key+id 能夠在前加上機器編號區分,key + id --- >機器惟一編號 + key + id (2):使用數據庫行鎖(單個數據庫的是時候,如何是分佈式數據庫也會出現問題),在須要插入id的表加上行鎖,防止數據重複致使程序異常! (3):使用分佈式鎖 bash

二:分佈式鎖簡介

網上有不少的講解分佈式鎖的文章,可是細細分析不少的代碼仍是有不少的問題的,以下代碼片斷摘自博文:服務器

public void lock(long timeout) {
        long nano = System.nanoTime();
        timeout *= 1000000;
        final Random r = new Random();
        try {
            while ((System.nanoTime() - nano) < timeout) {
                if (redisTemplate.getConnectionFactory().getConnection().setNX(key.getBytes(), LOCKED.getBytes())) {
                    redisTemplate.expire(key, EXPIRE, TimeUnit.SECONDS);
                    locked = true;
                    logger.debug("add RedisLock[" + key + "].");
                    break;
                }
                Thread.sleep(3, r.nextInt(500));
            }
        } catch (Exception e) {
        }
    }
	
複製代碼

上面的代碼博主也說了:若是長時間獲取不到,就會獲取鎖失敗,至關於沒加鎖!

這裏還有可能發生其餘問題:

(1)併發狀況,expire主動釋放鎖的時候,可能釋放的是別人的鎖(不懂請自行查詢相關資料

(2)Redis服務掛掉,鎖失敗,至關於沒加鎖!最好使用主從+哨兵提升 高可用

注:使用的時候要注意上面問題!!!

還有一種摘自博文: www.cnblogs.com/0201zcr/p/5… 這個博問分析的:

while (timeout >= 0) {
            long expires = System.currentTimeMillis() + expireMsecs + 1;
            String expiresStr = String.valueOf(expires); //鎖到期時間
            if (this.setNX(lockKey, expiresStr)) {
                // lock acquired
                locked = true;
                return true;
            }

            String currentValueStr = this.get(lockKey); //redis裏的時間
            if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
                //判斷是否爲空,不爲空的狀況下,若是被其餘線程設置了值,則第二個條件判斷是過不去的
                // lock is expired

                String oldValueStr = this.getSet(lockKey, expiresStr);
                //獲取上一個鎖到期時間,並設置如今的鎖到期時間,
                //只有一個線程才能獲取上一個線上的設置時間,由於jedis.getSet是同步的
                if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
                    //防止誤刪(覆蓋,由於key是相同的)了他人的鎖——這裏達不到效果,這裏值會被覆蓋,可是由於什麼相差了不多的時間,因此能夠接受

                    //[分佈式的狀況下]:如過這個時候,多個線程剛好都到了這裏,可是隻有一個線程的設置值和當前值相同,他纔有權利獲取鎖
                    // lock acquired
                    locked = true;
                    return true;
                }
            }
            timeout -= DEFAULT_ACQUIRY_RESOLUTION_MILLIS;

            /*
                延遲100 毫秒,  這裏使用隨機時間可能會好一點,能夠防止飢餓進程的出現,即,當同時到達多個進程,
                只會有一個進程得到鎖,其餘的都用一樣的頻率進行嘗試,後面有來了一些進行,也以一樣的頻率申請鎖,這將可能致使前面來的鎖得不到知足.
                使用隨機的等待時間能夠必定程度上保證公平性
             */
            Thread.sleep(DEFAULT_ACQUIRY_RESOLUTION_MILLIS);

        }
        
複製代碼

這個相比第一個完善了誤刪除key的問題,可是要合理的設置超時時間 (要了解具體加鎖的業務),不然的話,也會使鎖失效。

三:Redisson分佈式鎖的介紹和簡單的使用

Redisson的介紹能夠到:github.com/redisson/re… 這裏去了解!

我這裏說一下使用時候要注意的問題:

1:文檔裏面說明了支持Redis 2.8以上版本,支持Java1.6+以上版本。根據本身的環境選擇合適的版本!

2:2.8.1的redisson 須要使用 netty的jar包, 不然報錯:Hopper: java.lang.NoClassDefFoundError: io/netty/channel/EventLoopGroup。

3:2.8.1的redisson須要jackson 2.5+版本,不然報錯bjectMapper.addMixIn method not fond。

我寫了一個簡單的例子,本身也作了一下測試,使用的Redis主從+哨兵模式! demo的目錄結構,具體的源碼我放到github上面,地址:github.com/dufyun/lear…

這裏寫圖片描述

注:這裏必定要先安裝Redis服務,若是沒有安裝Redis服務,請參考這篇:blog.csdn.net/u010648555/… 若是Redis服務安裝到服務器上面,請修改代碼中的Redis地址和端口!不然運行不起了!

運行這個類UUidGeneratorLockTest就能夠看到效果!測試結果我也在readme.txt進行了總結!

若是在測試和學習的過程當中有疑問,能夠隨時和我聯繫,也能夠加左側的羣或者QQ互相探討!謝謝!

四:總結

這個時代,信息爆炸,各類技術博文之間互相參考,真正的問題可能沒有暴露出來,真正好的文章仍是須要鑑別的!(我本身也會參考一些文章,可是我都會進行一些本身驗證,一個是爲準確性,一個加深本身的對知識的認識)

我也要反思,本身以前也寫過一些博文,也是遇到問題了,去網上搜一些解決方案,不少方案確實是理論上能夠解決當前遇到的問題,當時去深究,就會發現不少的不完整性!

多思考,多測試!讓代碼可以更加高效、健壯和安全!

五:參考博文

Redis實現分佈式鎖全局鎖—Redis客戶端Redisson中分佈式鎖RLock實現
分佈式鎖的幾種實現方式


謝謝你的閱讀,若是您以爲這篇博文對你有幫助,請點贊或者喜歡,讓更多的人看到!祝你天天開心愉快!



無論作什麼,只要堅持下去就會看到不同!在路上,不卑不亢!

願你我在人生的路上能都變成最好的本身,可以成爲一個獨擋一面的人

© 天天都在變得更好的阿飛雲

相關文章
相關標籤/搜索