文章目录
- 1. 避免共享状态(无状态/不可变)
- 2.线程封闭
- 3. 加锁同步
- 常用方式:
- 4. 使用线程安全的类/容器
- 5. 使用原子操作(CAS)
- 6. 合理设计并发模型
- 7. 使用高级并发工具
解决线程安全问题,核心目标是确保多个线程在并发访问共享资源时,程序的行为仍然正确、一致、可预测。可以从以下几个关键方面入手:
1. 避免共享状态(无状态/不可变)
“不共享,就安全”
- 使用不可变对象:如
String、Integer、LocalDateTime等,一旦创建无法修改。 - 设计无状态类:不持有实例变量,或仅持有只读数据。
- 使用局部变量:方法内部的变量天然线程私有。
✅ 优点:无需同步,性能最高,最安全。
2.线程封闭
让数据只属于一个线程
- ThreadLocal:为每个线程提供独立副本。
privatestaticfinalThreadLocal<SimpleDateFormat>formatter=ThreadLocal.withInitial(()->newSimpleDateFormat("yyyy-MM-dd"));注意:需防止内存泄漏(在线程池中使用后及时
remove())。
3. 加锁同步
控制对共享资源的互斥访问
常用方式:
- synchronized 关键字
publicsynchronizedvoidincrement(){count++;}// 或publicvoidmethod(){synchronized(lock){/* 临界区 */}}- ReentrantLock(显式锁)
privatefinalLocklock=newReentrantLock();publicvoiddoSomething(){lock.lock();try{/* 临界区 */}finally{lock.unlock();}}✅ 适用场景:必须修改共享可变状态时。
⚠️ 风险:死锁、性能下降、锁粒度不当。
4. 使用线程安全的类/容器
直接使用JDK提供的并发工具
| 类型 | 安全替代方案 |
|---|---|
| List | CopyOnWriteArrayList,Collections.synchronizedList() |
| Set | ConcurrentHashMap.newKeySet(),CopyOnWriteArraySet |
| Map | ConcurrentHashMap |
| Queue | ConcurrentLinkedQueue,BlockingQueue实现类 |
| 计数器 | AtomicInteger,LongAdder |
| 示例: |
privatefinalConcurrentHashMap<String,User>userCache=newConcurrentHashMap<>();privatefinalAtomicIntegercounter=newAtomicInteger(0);5. 使用原子操作(CAS)
无锁并发,基于硬件指令
java.util.concurrent.atomic包:AtomicInteger,AtomicReference,AtomicStampedReference(解决 ABA 问题)
- 适用于简单状态更新(计数、标志位、引用替换等)
✅ 优点:高性能,无阻塞。
❌ 局限:不适合复杂逻辑。
6. 合理设计并发模型
从架构层面规避竞争
- 分段锁 / 分片(Sharding):如
ConcurrentHashMap将数据分段加锁。 - 消息队列 / Actor 模型:通过单线程处理特定任务(如 Disruptor、Akka)。
- 写时复制(Copy-On-Write):读多写少场景(如
CopyOnWriteArrayList)。 - 避免全局状态:将共享状态拆分为线程本地或请求级上下文。
7. 使用高级并发工具
- CountDownLatch / CyclicBarrier / Semaphore:协调线程执行。
- CompletableFuture / ExecutorService:异步编程,避免手动管理线程。
- StampedLock:读多写少场景的高性能读写锁(支持乐观读)。