原子操作
原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何context switch线程切换
分布式锁
分布式锁本质上要实现的目标就是在 Redis 里面占一个“茅坑”,当别的进程也要来占时,发现已经有人蹲在那里了,就只好放弃或者稍后再试;对于执行时间超过锁定时间的,需要锁具有重入性
Java 版本的可重入锁(基于ThreadLocal和引用计数)
public class RedisWithReentrantLock {private ThreadLocal<Map> lockers = new ThreadLocal<>();private Jedis jedis;public RedisWithReentrantLock(Jedis jedis) {this.jedis = jedis;}private boolean _lock(String key) {return jedis.set(key, "", "nx", "ex", 5L) != null;}private void _unlock(String key) {jedis.del(key);}private Map <String, Integer> currentLockers() {Map <String, Integer> refs = lockers.get();if (refs != null) {return refs;}lockers.set(new HashMap<>());return lockers.get();}public boolean lock(String key) {Map refs = currentLockers();Integer refCnt = refs.get(key);if (refCnt != null) {refs.put(key, refCnt + 1);return true;}boolean ok = this._lock(key);if (!ok) {return false;}refs.put(key, 1);return true;}public boolean unlock(String key) {Map refs = currentLockers();Integer refCnt = refs.get(key);if (refCnt == null) {return false;}refCnt -= 1;if (refCnt > 0) {refs.put(key, refCnt);} else {refs.remove(key);this ._unlock(key);}return true;}public static void main(String[] args) {Jedis jedis = new Jedis();RedisWithReentrantLock redis = new RedisWithReentrantLock(jedis);System.out.println(redis.lock("codehole"));System.out.println(redis.lock("codehole"));System.out.println(redis.unlock("codehole"));System.out.println(redis.unlock("codehole"));}
}
分布式锁线程加锁失败解决方案
仅供参考
1、直接抛出异常,通知用户稍后再试
2、设置锁等待时间,等待特定时间后重试
3、将请求转至延时队列,一会再重试