1. 程式人生 > >Java實現Redis分佈鎖

Java實現Redis分佈鎖

1、背景:

在多執行緒環境下,通常會使用鎖來保證有且只有一個執行緒來操作共享資源。比如:

object obj = new object();
lock (obj) 

//操作共享資源 
}

利用作業系統提供的鎖機制,可以確保多執行緒或多程序下的併發唯一操作。但如果在多機環境下就不能滿足了,當A,B兩臺機器同時操作C機器的共享資源時,就需要第三方的鎖機制來保證在分散式環境下的資源協調,也稱分散式鎖。

在分散式環境下(多節點主機)加鎖處理場景,如:秒殺、全域性遞增ID等等,需要對資源(變數)同步互斥。大部分的解決方案是基於DB實現的,Redis為單程序單執行緒模式,採用佇列模式將併發訪問變成序列訪問,且多客戶端對Redis的連線並不存在競爭關係。由於Redis是單執行緒模型,命令操作原子性,所以利用這個特性可以很容易的實現分散式鎖。


2、Redis有三個最基本屬性來保證分散式鎖的有效實現:

安全性: 互斥,在任何時候,只有一個客戶端能持有鎖。
活躍性A:沒有死鎖,即使客戶端在持有鎖的時候崩潰,最後也會有其他客戶端能獲得鎖,超時機制。

活躍性B:故障容忍,只有大多數Redis節點時存活的,客戶端仍可以獲得鎖和釋放鎖。

使用Redis實現分散式鎖,有兩個重要函式需要介紹

1)SETNX命令(SET if Not eXists)
語法:
SETNX key value
功能:
當且僅當 key 不存在,將 key 的值設為 value ,並返回1;若給定的 key 已經存在,則 SETNX 不做任何動作,並返回0。


2)GETSET命令
語法:
GETSET key value
功能:
將給定 key 的值設為 value ,並返回 key 的舊值 (old value),當 key 存在但不是字串型別時,返回一個錯誤,當key不存在時,返回nil。

3、程式碼:

package ct.tool;

import redis.clients.jedis.Jedis;

public class RedisDisLock {
	
	private static final long expired = 1000;//1秒超時
	//上鎖
	public static boolean acquireLock(Jedis jedis,String lock) {
	    // 1. 通過SETNX試圖獲取一個lock
	    boolean success = false;
	    long value = System.currentTimeMillis() + expired + 1;      
	    long acquired = jedis.setnx(lock, String.valueOf(value));
	    jedis.expire(lock, 1);//設定1秒超時
	    //SETNX成功,則成功獲取一個鎖
	    if (acquired == 1)  success = true;
	    //SETNX失敗,說明鎖被其他客戶端保持,檢查其是否已經超時
	    /*else {
	        long oldValue = Long.valueOf(jedis.get(lock));	       
	        if (oldValue < System.currentTimeMillis()) {//超時
	        	//獲取上一個鎖到期時間,並設定現在的鎖到期時間,
                //只有一個執行緒才能獲取上一個線上的設定時間,因為jedis.getSet是同步的
	            String getValue = jedis.getSet(lock, String.valueOf(value));
	            if (getValue !=null) {
	            	if (Long.valueOf(getValue) == oldValue) 
		                success = true; 
		            else success = false;// 已被其他程序捷足先登了
	            }            
	        }else //未超時,則直接返回失敗
	        	success = false;
	    }        */
	    return success;      
	}
	 
	//釋放鎖
	public static void releaseLock(Jedis jedis,String lock) {    
	    //long current = System.currentTimeMillis();       
	    // 避免刪除非自己獲取得到的鎖
	    //if (current < Long.valueOf(jedis.get(lock)))
	        jedis.del(lock); 
	}

}


程式碼應用中,要共享的程式碼段前加:
//枷鎖
	    	boolean lockFlag=true;
	    	while(lockFlag){//迴圈等待拿鎖
	    		if (RedisDisLock.acquireLock(jd,"o2o")) lockFlag=false;
	    	}

業務處理後,釋放:
RedisDisLock.releaseLock(jd, "o2o");


相關推薦

Java實現Redis分佈

1、背景: 在多執行緒環境下,通常會使用鎖來保證有且只有一個執行緒來操作共享資源。比如: object obj = new object(); lock (obj)  {  //操作共享資源  }利用作業系統提供的鎖機制,可以確保多執行緒或多程序下的併發唯一操作。但如果在多

Java實現Redis分散式

1、背景: 在多執行緒環境下,通常會使用鎖來保證有且只有一個執行緒來操作共享資源。比如: object obj = new object();lock (obj) { //操作共享資源 } 利用作業系統提供的鎖機制,可以確保多執行緒或多程序下的併發唯一操作。但如果在多機

Java 正確實現 redis 分散式

Java 正確實現 redis 分散式鎖 Java 正確實現 redis 分散式鎖 1 源起 2 我想要的效果 3 擼起袖子開幹 3.1 匯入 jedis 依賴

說說在JAVA中使用Redis,以及Redis分佈

只上程式碼和說明,其他的不講了,權當做個筆記。 該程式碼使用了1年多,在高併發的情況下並無問題,所以分享給大家。 package util; import java.io.UnsupportedEncodingException; import java.net.So

註解形式實現,Redis分散式

Redis工具類參考我的博文:https://blog.csdn.net/weixin_38399962/article/details/82753763 一個註解就可以實現分散式鎖?這麼神奇麼? 首先定義註解: /** * Description:分散式Redis鎖 * User:

如何實現一個分佈

基本概念 為何需要分散式鎖? 傳統環境中的情況: 在程式開發過程中不得不考慮的就是併發問題。在java中對於同一個jvm而言,jdk已經提供了lock和同步等。但是在分散式情況下,往往存在多個程序對一些資源產生競爭關係,而這些程序往往在不同的機器上,這個時候jdk中提供

Redisson實現Redis分散式的N種姿勢

前幾天發的一篇文章《Redlock:Redis分散式鎖最牛逼的實現》,引起了一些同學的討論,也有一些同學提出了一些疑問,這是好事兒。本文在講解如何使用Redisson實現Redis普通分散式鎖,以及Redlock演算法分散式鎖的幾種方式的同時,也附帶解答這些同學的一些疑問。 Redis幾種架構 Redis

java實現一個行(RowLock)

java 版本的資料庫行鎖,使用wait/notify實現,當然可以使用別的方式如Lock下的await/signal 需求使用java寫一個類,這個類有一個lock(String identifie

基於官方推薦的Redisson實現Redis分散式

RedLock 簡介 在不同程序需要互斥地訪問共享資源時,分散式鎖是一種非常有用的技術手段。實現高效的分散式鎖有三個屬性需要考慮: 安全屬性:互斥,不管什麼時候,只有一個客戶端持有鎖 效率屬性A:不會死鎖 效率屬性B:容錯,只要大多數redis節點能夠正常工作,客戶端端都能獲取和

PHP實現Redis單據,防止併發重複寫入

一、寫在前面: 在整個供應鏈系統中,會有很多種單據(採購單、入庫單、到貨單、運單等等),在涉及寫單據資料的介面時(增刪改操作),即使前端做了相關限制,還是有可能因為網路或異常操作產生併發重複呼叫的情況,導致對相同單據做相同的處理; 為了防止這種情況對系統造成

python實現redis分散式

#!/usr/bin/env python # coding=utf-8 import time import redis class RedisLock(object): def __i

java實現Redis工具類 RedisUtil.java

package shop.javaweb.utils; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; imp

Java實現redis事務

1.  正常執行的事務 @Test public void test() { Jedis jedis = new Jedis("localhost");

基於AOP實現redis分散式

如果你的系統是分散式叢集部署的,那麼傳統的synchorinzed或者jdk1.5提供的Lock都是依賴本地的jvm虛擬機器提供鎖服務,分散式服務中多jvm是無法同享鎖資訊的,故無法提供鎖。 分散式場景中資料一致性問題一直是一個比較重要的話題。分散式的CAP理論告訴我們任何一

java實現redis的哨兵模式的呼叫

1、安裝redis 叢集,1主1從 也可以是多主多從   redis 詳細今後會在以後的文章中寫出 配置redis-master 的配置檔案 redis.conf 配置程式碼   port 6379   daemonize yes   #protected-mode

【隨筆】Java 基於Redis分散式

定義介面 public interface IDistributedLock { boolean tryLock(String var1, Object var2); boolean tryLock(String var1, Object var2, i

Java實現Redis的雜湊(Hash)命令

本編文章知識簡單的實現了redis 的增刪改查,指令不是很全還請大家見諒 package com.huadian.Hash; import com.huadian.redisUntil.JedisPoolUntil; import org.junit.After; i

javaredis分散式的工具類

package com.qlchat.redis.cache; import java.util.*; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory;

JAVA實現redis超時失效key 的監聽觸發

過期事件通過Redis的訂閱與釋出功能(pub/sub)來進行分發。 而對超時的監聽呢,並不需要自己釋出,只有修改配置檔案redis.conf中的:notify-keyspace-events Ex,

Java實現Redis的集合(set)命令

下面測試redis的集合set的型別,註釋裡面的程式碼是linux中redis命令 package com.huadian.set; import com.huadian.redisUntil.JedisPoolUntil; import org.junit.Befo