基於redis的分散式鎖的實現
阿新 • • 發佈:2019-01-14
之前一直對分散式鎖有所思考。一直覺得現在高效能的redis是個不錯的選擇;
今天也嘗試著寫了一個基於redis的分散式鎖工具
LockUtil.java
package yyf.Jedis.toolsByRedis; import java.util.concurrent.atomic.AtomicInteger; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; /** * 基於redis的分散式鎖工具 * * @author yuyufeng * */ public class LockUtil { // 獲取redis static JedisPool jedisPool; static { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(100); config.setMaxIdle(5); config.setMaxWaitMillis(1000); config.setTestOnBorrow(false); // 構造池 jedisPool = new JedisPool(config, "127.0.0.1", 6379, 1000, "12345"); } // redis鍵值字首標識 private final static String PREFIX = "LOCK-FLAG-"; // 預設獲取鎖的等待時間 private final static Integer WAITTIME = 200; /** * 獲取鎖 * * @param uid:鎖的唯一標識 * @param expire:鎖自動釋放時間 * @return true:獲得鎖;false:鎖已被佔用 */ public static Boolean getLock(String uid, Integer expire) { if (expire < 0) { return false; } Long beginTime = System.currentTimeMillis(); do { Jedis jedis = jedisPool.getResource(); //防止程式出錯設定鍵值不失效 if(jedis.ttl(PREFIX + uid) == -1){ jedis.expire(PREFIX + uid, expire); } Long res = jedis.incr(PREFIX + uid); if (res == 1) { jedis.expire(PREFIX + uid, expire); if (jedis != null) { try { jedis.close(); } catch (Exception e1) { e1.printStackTrace(); } } return true; } if (jedis != null) { try { jedis.close(); } catch (Exception e1) { e1.printStackTrace(); } } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.print("."); } while ((System.currentTimeMillis() - beginTime) < WAITTIME); return false; } /** * 獲取鎖 * * @param uid:鎖的唯一標識 * @param expire:鎖自動釋放時間 * @param timeout:超時等待時間 * @return true:獲得鎖;false:鎖已被佔用 */ public static Boolean getLock(String uid, Integer expire, Integer timeout) { if (expire < 0) { return false; } Long beginTime = System.currentTimeMillis(); do { Jedis jedis = jedisPool.getResource(); //防止程式出錯設定鍵值不失效 if(jedis.ttl(PREFIX + uid) == -1){ jedis.expire(PREFIX + uid, expire); } Long res = jedis.incr(PREFIX + uid); if (res == 1) { jedis.expire(PREFIX + uid, expire); if (jedis != null) { try { jedis.close(); } catch (Exception e1) { e1.printStackTrace(); } } return true; } if (jedis != null) { try { jedis.close(); } catch (Exception e1) { e1.printStackTrace(); } } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.print("."); } while ((System.currentTimeMillis() - beginTime) < timeout); return false; } /** * 手動釋放鎖 * * @param uid:鎖的唯一標識 */ public static void returnLock(String uid) { Jedis jedis = jedisPool.getResource(); jedis.del(PREFIX + uid); if (jedis != null) { try { jedis.close(); } catch (Exception e1) { e1.printStackTrace(); } } System.out.println("手動釋放鎖:" + uid); } /** * 測試 * * @param args */ public static void main(String[] args) { AtomicInteger ai = new AtomicInteger(1); AtomicInteger count = new AtomicInteger(0); for (int i = 0; i < 30; i++) { new Thread() { @Override public void run() { String uid = "a" + ai.incrementAndGet() % 10; // 獲取鎖,並設定10秒失效 Boolean lock = LockUtil.getLock(uid, 10); System.out.println(uid + "取鎖結果:" + lock); if (lock) { // dosomething.. count.incrementAndGet(); } System.out.println("當前獲取鎖的數量:"+count); } }.start(); } // 手動解鎖測試,超時測試 //Boolean lock = LockUtil.getLock("testReturnKey", 1); //System.out.println("testReturnKey" + "取鎖結果:" + lock); // LockUtil.returnLock("testReturnKey"); } }
給出其中連續的兩次執行測試結果吧:
第一次執行(預期獲得10個鎖):
a7取鎖結果:true 當前獲取鎖的數量:1 a2取鎖結果:true 當前獲取鎖的數量:2 a1取鎖結果:true 當前獲取鎖的數量:3 a3取鎖結果:true 當前獲取鎖的數量:4 a9取鎖結果:true 當前獲取鎖的數量:5 a8取鎖結果:true 當前獲取鎖的數量:6 a0取鎖結果:true 當前獲取鎖的數量:7 a5取鎖結果:true 當前獲取鎖的數量:8 a6取鎖結果:true 當前獲取鎖的數量:9 a4取鎖結果:true 當前獲取鎖的數量:10 ......................a4取鎖結果:false a7取鎖結果:false 當前獲取鎖的數量:10 當前獲取鎖的數量:10 ..a5取鎖結果:false a6取鎖結果:false 當前獲取鎖的數量:10 ...當前獲取鎖的數量:10 a3取鎖結果:false a6取鎖結果:false a9取鎖結果:false 當前獲取鎖的數量:10 當前獲取鎖的數量:10 當前獲取鎖的數量:10 .a5取鎖結果:false 當前獲取鎖的數量:10 .a8取鎖結果:false 當前獲取鎖的數量:10 ..a4取鎖結果:false a0取鎖結果:false 當前獲取鎖的數量:10 當前獲取鎖的數量:10 ..a1取鎖結果:false a3取鎖結果:false 當前獲取鎖的數量:10 當前獲取鎖的數量:10 .a0取鎖結果:false 當前獲取鎖的數量:10 .a9取鎖結果:false 當前獲取鎖的數量:10 .a7取鎖結果:false 當前獲取鎖的數量:10 .a2取鎖結果:false 當前獲取鎖的數量:10 .a8取鎖結果:false 當前獲取鎖的數量:10 ..a1取鎖結果:false a2取鎖結果:false 當前獲取鎖的數量:10 當前獲取鎖的數量:10
接著馬上執行第二次(預期就是10秒內全部不能獲得鎖):
...............................a6取鎖結果:false 當前獲取鎖的數量:0 .a0取鎖結果:false 當前獲取鎖的數量:0 .a5取鎖結果:false 當前獲取鎖的數量:0 .a9取鎖結果:false .a3取鎖結果:false 當前獲取鎖的數量:0 .a7取鎖結果:false 當前獲取鎖的數量:0 .a1取鎖結果:false 當前獲取鎖的數量:0 當前獲取鎖的數量:0 .a9取鎖結果:false 當前獲取鎖的數量:0 .a8取鎖結果:false .a7取鎖結果:false 當前獲取鎖的數量:0 .a3取鎖結果:false 當前獲取鎖的數量:0 ...當前獲取鎖的數量:0 .a8取鎖結果:false 當前獲取鎖的數量:0 a4取鎖結果:false 當前獲取鎖的數量:0 a0取鎖結果:false 當前獲取鎖的數量:0 a2取鎖結果:false 當前獲取鎖的數量:0 .a4取鎖結果:false 當前獲取鎖的數量:0 ...a1取鎖結果:false a9取鎖結果:false 當前獲取鎖的數量:0 a5取鎖結果:false 當前獲取鎖的數量:0 當前獲取鎖的數量:0 ....a2取鎖結果:false .a0取鎖結果:false 當前獲取鎖的數量:0 a1取鎖結果:false a7取鎖結果:false .a4取鎖結果:false 當前獲取鎖的數量:0 a2取鎖結果:false 當前獲取鎖的數量:0 ..a8取鎖結果:false .當前獲取鎖的數量:0 當前獲取鎖的數量:0 a6取鎖結果:false 當前獲取鎖的數量:0 .a5取鎖結果:false a3取鎖結果:false 當前獲取鎖的數量:0 當前獲取鎖的數量:0 當前獲取鎖的數量:0 當前獲取鎖的數量:0 .a6取鎖結果:false 當前獲取鎖的數量:0
效果還是很理想的。有待實踐吧。