占位ing
通过zookeeper、consul等分布式协调服务实现
通过redis的原子操作实现
zookeeper
分布式排他锁
分布式读写锁:
读锁
写锁
可参阅:https://www.cnblogs.com/z-sm/p/5691752.html
redis
分布式排他锁:借助redis的setnx原子操作。代码:
public class CourseExpEditDistributedLockUtil { /** 获取锁(可重入),在开始编辑课程或实验前调用。 */ public static boolean lock(String entityId, LockedEntityTypeEnum entityType, String curUserId) { String redisKey = generateDistributedLockKey(entityId, entityType); String redisValue = generateDistributedLockValue(curUserId); {// 判断是否是重入操作,若是则直接成功 String tmpVal = JedisPoolClientUtil.get(redisKey); if (null != tmpVal && tmpVal.equals(redisValue)) { return true; } } // 通过Redis setnx原子操作设置分布式锁。为防止获得锁后没释放,设置锁的最长持有时间 String res = JedisPoolClientUtil.set(redisKey, redisValue, "nx", "ex", (long) (1 * 3600));// 设置值以获取分布式锁,并设置持有该锁的最长时间 return null != res; // ApiCustomException.assertTrue(ApiErrorCode.FORBIDDEN, null != res, // "目标课程或实验正在被其他人编辑,请稍候"); } /** 释放锁,已持有锁方可释放。在课程或实验编辑完后调用。 */ public static boolean unLock(String entityId, LockedEntityTypeEnum entityType, String curUserId) { String redisKey = generateDistributedLockKey(entityId, entityType); String redisValueExcepted = generateDistributedLockValue(curUserId); String redisValueReal = JedisPoolClientUtil.get(redisKey); if (null != redisValueReal && redisValueReal.equals(redisValueExcepted)) { JedisPoolClientUtil.del(redisKey); return true; } else { return false; } // ApiCustomException.assertTrue(ApiErrorCode.NOT_EXIST_DATA, null != // redisValueReal && // redisValueReal.equals(redisValueExcepted), // "当前用户未持有目标课程或实验的编辑权"); } /** 锁的key为目标Entity的信息 */ private static String generateDistributedLockKey(String entityId, LockedEntityTypeEnum type) { return String.format("DistributedLock_%s_%s", type, entityId); } /** 锁的value */ private static String generateDistributedLockValue(String curUserId) { return curUserId; } public static enum LockedEntityTypeEnum { COURSE, EXPERIMENT, CATALOG, COURSE_TRANSLATION, EXPERIMENT_TRANSLATION, CATALOG_TRANSLATION; } }
...