我在我的代码中使用 ConcurrentSkipListMap 并且我想确保方法是并发安全的。
public synchronized UserLogin getOrCreateLogin(Integer userId) {
// new user
if (!sessionCache.containsKey(userId)) {
String sessionKey = sessionKeyPool.getKey();
sessionCache.putIfAbsent(userId, sessionKey);
return userSessions.computeIfAbsent(sessionKey, userLogin -> new UserLogin(userId, sessionKey));
} else { // old user, check session
String oldSessionKey = sessionCache.get(userId);
UserLogin old = userSessions.get(oldSessionKey);
if (!old.isExpired()) return old;
log.info("Session expired! Create another. User id: " + userId + ", last login: " + old.getStartTime());
String newKey = sessionKeyPool.getKey();
UserLogin another = new UserLogin(userId, newKey);
userSessions.replace(newKey, another);
sessionCache.replace(userId, newKey);
return another;
}
}
我知道地图会自动执行containsKey()
,get
等等。但并不意味着整个块不能被两个线程同时访问,而是至少在行与行之间保护了happens-before关系(第一个线程到达该行将首先退出该行)。但是,那么如何实际使用这些方法来获得可组合且一致的结果呢?如何锁定这些行?
如何在不影响输出数据一致性的情况下锁定以获得最精细的粒度?