之前一直對分散式鎖有所思考。一直覺得現在高效能的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

效果還是很理想的。有待實踐吧。

.