synchronized块比修饰整个方法更优,应锁私有final对象且粒度最小;AtomicInteger适用于单变量原子操作;ReentrantLock支持中断、超时和公平性;ConcurrentHashMap优于Hashtable,但复合操作仍需显式同步。

用 synchronized 保护临界区最直接,但别锁整个方法
当多个线程同时读写同一个共享变量(比如 int count),不加控制就会出现“写了没生效”或“覆盖彼此结果”的情况。最常用也最稳妥的方式是用 synchronized 块包裹真正需要互斥的代码段,而不是直接修饰整个方法。
- 锁对象要明确:优先用私有
final Object lock = new Object(),避免用this或类对象,防止外部干扰 - 粒度越小越好:只锁修改共享状态的几行,比如
count++前后,不要把日志、网络调用等无关操作包进去 - 注意死锁风险:如果必须嵌套锁,确保所有线程按相同顺序获取锁
public class Counter {
private int count = 0;
private final Object lock = new Object();
public void increment() {
synchronized (lock) {
count++; // 这里才是临界区
}
}}
AtomicInteger 适合简单计数,但不能替代复杂业务逻辑锁
对于自增、自减、CAS 比较设置这类单变量原子操作,AtomicInteger 是无锁且高效的方案。它底层用 CPU 的 cmpxchg 指令实现,比 synchronized 开销低,但仅限于“一个变量 + 一个原子动作”场景。
- 支持
incrementAndGet()、compareAndSet(expected, updated)等方法,返回值可判断是否成功 - 不能用于跨多个变量的原子更新,比如“先查余额再扣款”,此时仍需
synchronized或ReentrantLock - 注意内存可见性:它本身保证 volatile 语义,但和非原子字段混用时,其他字段仍可能被重排序影响
private AtomicInteger balance = new AtomicInteger(100);public boolean withdraw(int amount) { while (true) { int current = balance.get(); if (current < amount) return false; if (balance.compareAndSet(current, current - amount)) { return true; } // CAS 失败,重试 } }
用 ReentrantLock 实现可中断、超时、公平性控制
当需要比 synchronized 更精细的控制时,ReentrantLock 是更灵活的选择。它支持尝试获取锁、设定等待超时、响应线程中断,还能选择是否启用公平策略。
千博购物系统.Net能够适合不同类型商品,为您提供了一个完整的在线开店解决方案。千博购物系统.Net除了拥有一般网上商店系统所具有的所有功能,还拥有着其它网店系统没有的许多超强功能。千博购物系统.Net适合中小企业和个人快速构建个性化的网上商店。强劲、安全、稳定、易用、免费是它的主要特性。系统由C#及Access/MS SQL开发,是B/S(浏览器/服务器)结构Asp.Net程序。多种独创的技术使
立即学习“Java免费学习笔记(深入)”;
- 必须显式
lock()和unlock(),且unlock()务必放在finally块中,否则可能永久持锁 -
tryLock(1, TimeUnit.SECONDS)可避免无限阻塞;lockInterruptibly()让线程在等待时能被interrupt() - 公平锁(
new ReentrantLock(true))会按请求顺序排队,但吞吐量通常更低,非必要不开启
private ReentrantLock lock = new ReentrantLock();public void transfer(Account from, Account to, int amount) { try { if (!lock.tryLock(2, TimeUnit.SECONDS)) { throw new RuntimeException("Lock timeout"); } // 执行转账逻辑 } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } }
集合类选错会导致隐式并发问题,优先用 ConcurrentHashMap 而非 Hashtable
很多人以为 Vector 或 Hashtable 是线程安全的“万能解”,其实它们只是方法加了 synchronized,整体性能差,且无法支持复合操作的原子性(比如“检查是否存在再 put”)。
-
ConcurrentHashMap分段锁(JDK 7)或 CAS + synchronized(JDK 8+),读操作完全无锁,写操作只锁对应桶,吞吐高 - 它提供
computeIfAbsent()、merge()等原子方法,可安全实现“不存在则初始化”这类逻辑 - 不要用
Collections.synchronizedMap()包装HashMap,它只是给每个方法加锁,依然无法解决迭代过程中的并发修改异常
private ConcurrentHashMapcache = new ConcurrentHashMap<>(); public Integer getOrCompute(String key, Supplier
supplier) { return cache.computeIfAbsent(key, k -> supplier.get()); }
实际编码中最容易忽略的是:复合操作的原子性不是靠单个工具类自动保障的。哪怕用了 ConcurrentHashMap,如果先 get() 再 put(),中间仍可能被其他线程插入。这种时候,要么换用它的原子方法,要么退回到显式锁。









