1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
| package io.binghe.concurrent.chapter19.service.impl;
import io.binghe.concurrent.chapter19.service.RedisDistributeLock; import io.binghe.concurrent.chapter19.task.UpdateLockTimeoutTask; import io.binghe.concurrent.chapter19.utils.ThreadUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.stereotype.Service;
import java.util.Collections; import java.util.concurrent.TimeUnit;
@Service("redisDistributeLockV8") public class RedisDistributeLockV9Impl implements RedisDistributeLock { @Autowired private StringRedisTemplate stringRedisTemplate; private ThreadLocal<String> threadLocal = new ThreadLocal<String>(); private ThreadLocal<Integer> threadLocalCount = new ThreadLocal<Integer>(); @Override public boolean tryLock(String key, long timeout, TimeUnit unit) { Boolean isLocked = false; if (threadLocal.get() == null){ String currentThreadId = this.getCurrentThreadId(); threadLocal.set(currentThreadId); isLocked = stringRedisTemplate.opsForValue().setIfAbsent(key, currentThreadId, timeout, unit);
if (!isLocked){ for (;;){ isLocked = stringRedisTemplate.opsForValue().setIfAbsent(key, currentThreadId, timeout, unit); if (isLocked){ break; } } } new Thread(new UpdateLockTimeoutTask(currentThreadId, stringRedisTemplate, key)).start();
}else{ isLocked = true; } if (isLocked){ Integer count = threadLocalCount.get() == null ? 0 : threadLocalCount.get(); threadLocalCount.set(++count); } return isLocked; }
@Override public void releaseLock(String key) { String currentThreadId = stringRedisTemplate.opsForValue().get(key); if (threadLocal.get().equals(currentThreadId)){ Integer count = threadLocalCount.get(); if (count == null || --count <= 0){ stringRedisTemplate.delete(key); threadLocal.remove(); threadLocalCount.remove();
String updateTimeThreadId = stringRedisTemplate.opsForValue().get(currentThreadId); if (updateTimeThreadId != null && !"".equals(updateTimeThreadId.trim())){ Thread updateTimeThread = ThreadUtils.getThreadByThreadId(Long.parseLong(updateTimeThreadId)); if (updateTimeThread != null){ updateTimeThread.interrupt(); stringRedisTemplate.delete(currentThreadId);
} } }else { threadLocalCount.set(count); }
} }
private static final String LUA_UN_LOCK = "if redis.call('get',KEYS[1]) == ARGV[1] then\n" + " return redis.call('del',KEYS[1])\n" + "else\n" + " return 0\n" + "end";
public boolean releaseLock2(String key, String lockValue) { DefaultRedisScript<String> redisScript = new DefaultRedisScript<>(); redisScript.setScriptText(LUA_UN_LOCK); redisScript.setResultType(String.class); Object result = stringRedisTemplate.execute(redisScript, Collections.singletonList(key), lockValue); return "1".equals(result.toString()); }
private String getCurrentThreadId(){ return String.valueOf(Thread.currentThread().getId()); } }
|