1.原理: 当同一个用户获取锁以后,会让该用户一直持有锁。一样 的用户再次获取,会根据原子性 ,lock返回true。redis
/** * 获取锁(非公平锁), 默认获取超时为2分钟 */ public boolean lock(){ return lock(GETLOCK_TIMEOUT/1000); } /** * 获取锁(非公平锁), 获取超时为timeoutSeconds秒 */ public boolean lock(int timeoutSeconds){ int timeout = timeoutSeconds*1000; while (timeout >= 0) { //在同一个JVM内,防止出现如下状况:当已经获取此锁的线程实际业务运行时间超过LOCK_EXPIRE_TIMEOUT时,此锁会再被其它线程获取 if(LOCKED_NAMES.contains(lockname)){ int sleeptime = random.nextInt(100)+100; try{Thread.sleep(sleeptime);} catch (InterruptedException e) {} timeout -= sleeptime; continue; } //当分布式程序获取同一个锁时,防止出现如下状况:当已经获取此锁的进程(物理机器)实际业务运行时间超过LOCK_EXPIRE_TIMEOUT时,此锁会再被其它进程(物理机器)获取 String hearbeatFlag = RedisCacheUtil.get(lockname + HEARTBEAT_SUFFIX , String.class ); if(hearbeatFlag!=null){ int sleeptime = random.nextInt(100)+100; try{Thread.sleep(sleeptime);} catch (InterruptedException e) {} timeout -= sleeptime; continue; } //锁到期时间 long expires = System.currentTimeMillis() + LOCK_EXPIRE_TIMEOUT + 1; boolean ok = setNX(expires); if (ok) { //System.out.println(Thread.currentThread().getName()+":得到锁成功,经过setNX"); LOCKED_NAMES.add(lockname); locked = true; return locked; } //获取当前锁信息 RedisLockValue redisLockValue = get(); if (redisLockValue != null && redisLockValue.getExpireTime() < System.currentTimeMillis()) { //利用getSet的原子性操做来设置并获取到旧值 RedisLockValue oldRedisLockValue = getSet(expires); //最早设置的获取锁 if (oldRedisLockValue != null && oldRedisLockValue.getToken().equals(redisLockValue.getToken())) { //System.out.println(Thread.currentThread().getName()+":得到锁成功,经过getSet"); LOCKED_NAMES.add(lockname); locked = true; return locked; } } //防止饥饿线程出现 采用随机休眠时间 int sleeptime = random.nextInt(100)+100; try{Thread.sleep(sleeptime);} catch (InterruptedException e) {} timeout -= sleeptime; } //若是已经超时,但只是由于此时缓存还有值,由于反序列化异常致使GET取不到时,解决死锁问题 try{Thread.sleep(300);} catch (InterruptedException e) {} RedisLockValue redisLockValue = get(); if(redisLockValue==null){ //强制删掉便可 LOCKED_NAMES.remove(lockname); RedisCacheUtil.delete(lockname); RedisCacheUtil.delete( lockname + HEARTBEAT_SUFFIX ); } return locked; }