您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# Java中线程安全问题举例分析
## 摘要
本文深入探讨Java多线程编程中的线程安全问题,通过典型场景案例、底层原理分析和解决方案对比,帮助开发者理解并规避常见的并发编程陷阱。文章包含5个实际案例、3类解决方案对比及JVM层原理解析,约5750字。
---
## 一、线程安全基础概念
### 1.1 什么是线程安全
当多个线程**同时访问**共享资源时,无论运行时环境采用何种调度方式,且无需额外同步协调,程序都能表现出**正确的行为**,则称该代码是线程安全的。
### 1.2 线程不安全的核心原因
- **竞态条件(Race Condition)**:操作执行结果依赖于线程执行顺序
- **内存可见性**:线程本地缓存与主内存不一致
- **指令重排序**:编译器/处理器优化导致的非预期执行顺序
---
## 二、典型线程安全问题案例
### 2.1 计数器失效问题
```java
public class UnsafeCounter {
private int count = 0;
public void increment() {
count++; // 非原子操作
}
}
问题分析:
1. count++
实际包含读取-修改-写入
三个操作
2. 当线程A读取count=0后,线程B也可能读取到0
3. 最终两个线程写入的值都是1,而非预期的2
字节码验证:
aload_0
dup
getfield #2 // 读取
iconst_1
iadd // +1
putfield #2 // 写入
List<String> list = new ArrayList<>();
// 线程1
list.forEach(System.out::println);
// 线程2
list.add("newItem");
异常类型:
- ConcurrentModificationException
- 根本原因:modCount检查机制失效
public class Singleton {
private static Singleton instance;
public static Singleton getInstance() {
if (instance == null) { // 检查1
instance = new Singleton(); // 操作2
}
return instance;
}
}
DCL问题:
1. 指令重排序可能导致对象未初始化完成就被引用
2. 使用volatile
可解决(JDK5+的JMM改进)
// 线程A
synchronized(account1) {
synchronized(account2) {
transfer(account1, account2);
}
}
// 线程B
synchronized(account2) {
synchronized(account1) {
transfer(account2, account1);
}
}
死锁四要素: 1. 互斥条件 2. 占有且等待 3. 不可抢占 4. 循环等待
public class VisibilityIssue {
private boolean flag = true;
public void worker() {
while (flag) { /* ... */ } // 可能无限循环
}
public void stop() {
flag = false;
}
}
JMM解释:
- 缺少happens-before关系
- 解决方案:volatile
或synchronized
特性 | synchronized | ReentrantLock |
---|---|---|
获取方式 | 自动获取释放 | 需要显式lock/unlock |
尝试非阻塞获取 | 不支持 | tryLock()支持 |
公平性 | 非公平 | 可配置公平策略 |
条件队列 | 单个 | 支持多个Condition |
CopyOnWriteArrayList
:适合读多写少ConcurrentHashMap
:分段锁技术(JDK7) vs CAS优化(JDK8+)BlockingQueue
:生产者-消费者模式首选public class AtomicCounter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet(); // CAS实现
}
}
CAS底层:
lock cmpxchg // x86指令级实现
屏障类型 | 作用 | 对应Java关键字 |
---|---|---|
LoadLoad | 禁止读-读重排序 | volatile读 |
StoreStore | 禁止写-写重排序 | volatile写 |
LoadStore | 禁止读-写重排序 | final字段初始化 |
StoreLoad | 全能屏障(开销最大) | volatile变量写后操作 |
| Mark Word (64bits) | Klass Word (64bits) |
|-----------------------------|---------------------|
| hashcode:25 | age:4 | biased_lock:1 | 01 | 对象类型指针 |
锁状态转换: 无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁
(全文共计约5750字,实际字数可能因排版略有差异) “`
注:本文为技术文章范例,实际开发中应结合具体JDK版本验证。如需完整代码示例或更深入分析,建议参考Oracle官方文档和并发编程权威资料。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。