线程安全的类 ≠ 线程安全的程序

java 复制代码
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() 问题,现在考虑这个逻辑:

java 复制代码
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() 等)。

  • 但它无法保证多个方法调用之间的逻辑是原子的

  • 这种"先判断再操作"的模式,需要外部同步

✅ 正确解决方案:对外层逻辑加锁(推荐)

java 复制代码
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) 来保护复合操作。

相关推荐
万法若空2 小时前
【算法-查找】查找算法
java·数据结构·算法
殳翰2 小时前
下服务器端开发流程及相关工具介绍(C++)
开发语言·c++
落寞的星星2 小时前
这个对象就包含了已经转换好的DFA和各种词法分析器运转所需要的参数。下一步,我们就可以用ScannerInfo对象创建出Scanner对象,请看下面的代码:
开发语言·c#
nothing&nowhere3 小时前
用 Python 做问卷数据清洗:无效样本检测与处理实战
开发语言·python·数据清洗·数据处理·问卷星·问卷星脚本·刷问卷
2601_961593423 小时前
Rust 开发环境配置繁琐?RustRover 开箱即用搞定编码调试
开发语言·后端·macos·rust
HZZD_HZZD4 小时前
DL/T 645-2026新国标深度解读与智能电表协议适配实战:从帧结构变化到Java采集器升级的全链路改造方案
java·开发语言
多加点辣也没关系6 小时前
JavaScript|第4章:类型转换
开发语言·javascript
聪慧的水蜜桃6 小时前
【YFIOs】用C#开发硬件之设备上云
开发语言·c#
yqcoder6 小时前
httpOnly 是什么,又有什么用?
开发语言·前端·javascript