import java.util.Vector;
public class Demo20 {
public static void main(String[] args) throws InterruptedException {
Vector<String> v = new Vector<>();
Thread t1 = new Thread(() -> {
if(v.isEmpty()) {
v.add("hello");
}
});
Thread t2 = new Thread(() -> {
if(v.isEmpty()) {
v.add("hello");
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(v);
}
}
假设你修复了 join() 问题,现在考虑这个逻辑:
if (v.isEmpty()) { // ← 检查
v.add("hello"); // ← 操作
}
虽然 isEmpty() 和 add() 各自是线程安全的(Vector 内部加锁),但这两个操作合起来不是原子的。
🧨 并发执行时的可能场景:
| 时间 | 线程 t1 | 线程 t2 |
|---|---|---|
| t1 | 调用 v.isEmpty() → 返回 true | — |
| t2 | — | 调用 v.isEmpty() → 返回 true |
| t3 | 执行 v.add("hello") | — |
| t4 | — | 执行 v.add("hello") |
→ 最终 v = ["hello", "hello"]
❌ 这违反了“只添加一次”的意图!
这就是 “复合操作非原子” 的经典问题。
✅ 为什么 Vector 的线程安全不够用?
-
Vector保证的是:单个方法调用是原子的(如add()、isEmpty()、get()等)。 -
但它无法保证多个方法调用之间的逻辑是原子的。
-
这种“先判断再操作”的模式,需要外部同步。
✅ 正确解决方案:对外层逻辑加锁(推荐)
public class Demo20 {
public static void main(String[] args) throws InterruptedException {
Vector<String> v = new Vector<>();
Thread t1 = new Thread(() -> {
synchronized (v) { // 使用 Vector 自身作为锁
if (v.isEmpty()) {
v.add("hello");
}
}
});
Thread t2 = new Thread(() -> {
synchronized (v) {
if (v.isEmpty()) {
v.add("hello");
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(v); // 输出: [hello] (只添加一次)
}
}
✅ 因为 Vector 本身用 this 加锁,所以我们也可以用 synchronized(v) 来保护复合操作。
10万+

被折叠的 条评论
为什么被折叠?



