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

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

相关推荐
唐青枫10 小时前
Java JDBC 实战指南:从 Connection 到事务和连接池
java
一个做软件开发的牛马11 小时前
MyBatis-Plus 从零实战:完整搭建可运行 Demo,BaseMapper 零 SQL、Wrapper 条件构造、分页插件与代码生成器详解
java·后端
用户37215742613511 小时前
Java 处理 PDF 图片:提取 PDF 中的图片,并压缩 PDF 图片体积
java
用户37215742613511 小时前
Java 打印 Word 文档:从基础打印到高级设置
java
用户3521802454751 天前
当 Prompt 学会"热更新":Spring Boot × Nacos3 AI 实战
java·spring boot·ai编程
东坡白菜1 天前
破局全栈:一个前端开发的Java入门实战记录(1)
java·全栈
唐青枫1 天前
Java Tomcat 实战指南:从 Servlet 容器到 Spring Boot 部署
java
wsaaaqqq1 天前
roudan:自由选择实体、灵活操作数据、快速写入数据库的 Java 框架
java
plainGeekDev1 天前
null 判断 → Kotlin 可空类型
android·java·kotlin
糖拌西瓜皮1 天前
Java开发者视角:深入理解Node.js异步编程模型
java·后端·node.js