分布式部署中不可避免用到分布式锁,目前比较常用的实现方式一般有基于数据库的乐观锁、基于redis的分布式锁和基于zookeeper的分布式锁。本文只说redis的实现方式,使用jedis作为连接器。
比较简单,直接上代码吧。
public class PaasLock { private static final String KEY_NNXX = "NX"; private static final String KEY_EXPX = "PX"; private static final String KEY_SUCCESS = "OK"; private static final String KEY_PREFIX = "paas.lock."; private static final Long KEY_RELEASE_NUM = 1L; //影响redis行数 private static Random RANDOM = new Random(100); private static final String REDIS_SCRIPT = "if redis.call(‘get‘, KEYS[1]) == ARGV[1] then return redis.call(‘del‘, KEYS[1]) else return 0 end"; private RedisDao redisDao; //封装jedis private String lockKey; public PaasLock() { //使用uuid生成不重复的key this(KEY_PREFIX + UUID.randomUUID().toString().replaceAll("-", "")); } //自定义key public PaasLock(String lockKey) { assert (lockKey == null || lockKey.isEmpty()); this.lockKey = KEY_PREFIX + lockKey; this.redisDao = SpringContexts.getBean(RedisDao.class); } /** * 获取锁 * * @param requestId * @param expireTime 毫秒,锁本身的超时时间 * @param waitTime 毫秒,获取锁等待时间 * @return true获取成功,false获取失败 */ public boolean tryGetDistributedLock(String requestId, long expireTime, long waitTime) { long nanoTime = System.nanoTime(); long timeOut = waitTime * 1000000; //纳秒10^6 = 1毫秒 try { //循环等待锁释放 while (System.nanoTime() - nanoTime < timeOut) { String res = redisDao.set(this.lockKey, requestId, KEY_NNXX, KEY_EXPX, expireTime); if (KEY_SUCCESS.equals(res)) { return true;// this.lock; } Thread.currentThread().sleep(5L, RANDOM.nextInt(30)); } } catch (Exception ex) { throw new RuntimeException("locking error", ex); } return false; } /** * 释放锁 * * @param requestId * @return */ public boolean releaseDistributedLock(String requestId) { Object result = redisDao.eval(REDIS_SCRIPT, Collections.singletonList(this.lockKey), Collections.singletonList(requestId)); if (KEY_RELEASE_NUM.equals(result)) { //只能释放自己的锁,防止被别的线程释放 System.out.println("release lock..,res=" + requestId); return true; } return false; } }
调用方法
PaasLock lock = new PaasLock(); if (lock.tryGetDistributedLock(resId, 3000, 30000)) { try { do ..... } finally { lock.releaseDistributedLock(resId); } } else{ ..... 其他处理 }
参考网上一些资料改造一下,比较简单,供大家参考。。。