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

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

相关推荐
IKUN家族3 小时前
Spring MVC(一)
java·spring·mvc
老马识途2.04 小时前
关于跨域问题的总结
java·前端
魔力女仆5 小时前
分享一个 JS 鼠标跟随贪吃蛇背景库
开发语言·javascript·计算机外设
都叫我大帅哥5 小时前
Java日期时间三十年战争:从Date考古到LocalDateTime革命,以及数据库与前端的那点事儿
java
Muscleheng5 小时前
SpringBoot 集成 DeepSeek 实现 RAG 文档问答
java·spring boot·ai·springai
2401_894915535 小时前
GEO 搜索优化完整源码从零部署:环境配置、集群搭建全流程
开发语言·python·tcp/ip·算法·unity
2501_936415696 小时前
可变参数&综合练习&斗地主游戏
java·windows·游戏
麻瓜老宋6 小时前
AI开发C语言应用按步走,表达式计算器calc的第二十二步,分号赋值链式修复、TOKEN_ASSIGN
c语言·开发语言·atomcode
极客先躯7 小时前
高级java每日一道面试题-2026年05月03日-实战篇[Docker]-如何实现容器化环境的数据加密?
java·运维·docker·容器·金融·加解密·高级面试
xqqxqxxq7 小时前
Java Socket 多人聊天室(私聊+群聊)技术笔记(V4版本)
java·网络·笔记