synchronized方法与特定资源锁:哪种实现更正确且性能更佳?
Java并发场景:synchronized方法 vs 特定资源加锁的正确性与性能对比
在Java并发场景中,使用synchronized方法(锁this)和针对特定资源加锁这两种方式,哪种实现更正确、性能更优?我的理解是,为需要避免并发修改的特定对象加锁效率更高,因为其他操作不同对象的线程可正常执行。
方式一:使用synchronized方法(锁this)
class Solution { public String getSessionKey(int user) { if (validateSessionKey(user)) { return someConcurrentHashMap.get(user).getKey(); } throw new InvalidSessionException(SESSION_NOT_FOUND); } public synchronized String createSession(int user) { if (validateSessionKey(user)) { return someConcurrentHashMap.get(user).getKey(); } UserSession session = new UserSession(user, generateSessionId(), LocalDateTime.now(ZoneOffset.UTC)); someConcurrentHashMap.put(user, session); sessionKeyToUser.put(session.getKey(), user); return someConcurrentHashMap.get(user).getKey(); } public int getUserBySessionKey(String sessionKey) { return sessionKeyToUser.getOrDefault(sessionKey, -1); } }
方式二:针对特定资源加锁
class Solution { private final Object createSessionLock = new Object(); public String getSessionKey(int user) { if (validateSessionKey(user)) { return someConcurrentHashMap.get(user).getKey(); } throw new InvalidSessionException(SESSION_NOT_FOUND); } public String createSession(int user) { // 若用户已存在则锁用户对象,否则锁全局新建锁 if (someConcurrentHashMap.containsKey(user)) { return createForExistingUser(user); } return createForNewUser(user); } public int getUserBySessionKey(String sessionKey) { return sessionKeyToUser.getOrDefault(sessionKey, -1); } private String createForExistingUser(int user) { if (validateSessionKey(user)) { return someConcurrentHashMap.get(user).getKey(); } UserSession userSession = someConcurrentHashMap.get(user); synchronized (userSession) { if (validateSessionKey(user)) { return someConcurrentHashMap.get(user).getKey(); } UserSession session = new UserSession(user, generateSessionId(), LocalDateTime.now(ZoneOffset.UTC)); someConcurrentHashMap.put(user, session); sessionKeyToUser.put(session.getKey(), user); return someConcurrentHashMap.get(user).getKey(); } } private String createForNewUser(int user) { if (validateSessionKey(user)) { return someConcurrentHashMap.get(user).getKey(); } synchronized (createSessionLock) { if (validateSessionKey(user)) { return someConcurrentHashMap.get(user).getKey(); } UserSession session = new UserSession(user, generateSessionId(), LocalDateTime.now(ZoneOffset.UTC)); someConcurrentHashMap.put(user, session); sessionKeyToUser.put(session.getKey(), user); return someConcurrentHashMap.get(user).getKey(); } } }
正确性分析
- synchronized方法(锁this):能保证线程安全,但锁粒度过大——整个
Solution实例的所有synchronized方法都会互相阻塞,哪怕是操作不同用户的createSession请求,也会被串行执行,存在不必要的等待逻辑。 - 特定资源加锁:采用细粒度锁+双重检查的设计,针对不同资源分别加锁,既保证了并发修改特定资源时的线程安全,又不会阻塞操作其他资源的线程,更贴合业务场景的正确性需求。需要注意:
- 针对已存在用户加锁时,同步块内的二次检查能避免因会话对象被替换导致的锁失效问题;
- 新建用户时使用全局锁,配合双重检查可防止多个线程重复创建同一用户的会话。
性能对比
你的理解完全正确,特定资源加锁的性能远优于synchronized方法:
- synchronized方法锁粒度大,所有调用
createSession的线程无论操作哪个用户都必须排队,高并发场景下会成为明显的性能瓶颈; - 特定资源加锁时,操作不同用户的线程可并行执行:比如线程A处理用户1的会话创建,线程B可同时处理用户2的会话创建,仅当多个线程操作同一用户(或同时创建新用户)时才会阻塞,大幅提升了并发吞吐量。
内容的提问来源于stack exchange,提问作者Sagar
相关产品推荐
相关产品推荐

