当前位置: 首页 > article >正文

20250214 随笔 线程安全 线程不安全

1. 什么是线程安全 & 线程不安全?

  • 线程安全(Thread-Safe):在多线程环境下访问同一个对象时,不会产生数据竞争、不会出现数据不一致的问题
  • 线程不安全(Not Thread-Safe):在多线程环境下,多个线程同时访问同一个对象可能会导致数据不一致,需要手动加锁或者使用线程安全的方式来操作。

2. StringBuffer 线程安全,StringBuilder 线程不安全

💡 主要区别在于

  • StringBuffer 是线程安全的,因为它的很多方法都加了 synchronized 关键字。
  • StringBuilder 是线程不安全的,因为它没有加 synchronized,多线程访问时可能会出现数据不一致问题。
🔹 StringBuffer(线程安全)
StringBuffer sb = new StringBuffer("Hello");

// 多线程修改同一个 StringBuffer 对象
Thread t1 = new Thread(() -> {
    sb.append(" World");
});

Thread t2 = new Thread(() -> {
    sb.append(" Java");
});

t1.start();
t2.start();
t1.join();
t2.join();

System.out.println(sb); // 结果是可预测的,因为 append() 方法是同步的

🔹 StringBuffer 内部的方法(如 append()insert())都加了 synchronized,保证了 同一时刻只有一个线程可以修改 StringBuffer 对象,所以它是 线程安全的


🔹 StringBuilder(线程不安全)
StringBuilder sb = new StringBuilder("Hello");

// 多线程修改 StringBuilder
Thread t1 = new Thread(() -> {
    sb.append(" World");
});

Thread t2 = new Thread(() -> {
    sb.append(" Java");
});

t1.start();
t2.start();
t1.join();
t2.join();

System.out.println(sb); // 可能输出 Hello World Java,也可能出现乱码

🔹 StringBuilder 没有 synchronized,多个线程同时访问时,可能会发生数据错乱,如

Hello WorldJava
Hello JavaWorld
Hello WJavorld

💡 因为多个线程可以同时修改 StringBuilder,导致数据写入时发生竞争,出现不可预测的情况


3. StringBuffer & StringBuilder 内部实现区别

📌 StringBuffer 使用 synchronized,保证线程安全

public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

🔹 append() 方法使用了 synchronized,意味着同一时刻只有一个线程能执行它,这样就保证了线程安全

📌 StringBuilder 没有 synchronized,线程不安全

public StringBuilder append(String str) {
    super.append(str);
    return this;
}

🔹 append() 方法没有 synchronized,多个线程同时修改时会产生数据竞争


4. 线程安全 vs 线程不安全,如何选择?

特性StringBuffer(线程安全)StringBuilder(线程不安全)
是否线程安全✅ 是❌ 不是
是否使用 synchronized✅ 是(同步)❌ 不是(无锁)
适用场景多线程环境(如 Web 服务器、并发任务)单线程环境(普通字符串拼接)
性能较慢(加锁有性能损耗)更快(无锁操作)
替代方案StringBuilder + synchronizedLock适用于单线程,性能更好

💡 如何选择?

  • 单线程:使用 StringBuilder,性能更高
  • 多线程:使用 StringBuffer,防止数据竞争
  • 多线程但性能要求高?可以使用 StringBuilder + synchronizedLock

5. 线程安全一定好?为什么有线程不安全的 StringBuilder?

💡 线程安全的代价是“性能下降”

  • StringBuffer 每次操作都需要 synchronized,即使单线程也会加锁,影响性能
  • StringBuilder 不加锁,在单线程下性能更快,适合大多数情况

示例:StringBuffer 在单线程下的性能劣势

long startTime = System.nanoTime();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 100000; i++) {
    sb.append("Java");
}
long endTime = System.nanoTime();
System.out.println("StringBuffer 时间:" + (endTime - startTime) + " ns");

对比:StringBuilder 在单线程下的性能

long startTime = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100000; i++) {
    sb.append("Java");
}
long endTime = System.nanoTime();
System.out.println("StringBuilder 时间:" + (endTime - startTime) + " ns");

💡 单线程下,StringBuilder 速度明显更快,因为它没有加锁!


6. 线程安全 & 线程不安全的选择策略

场景推荐选择
单线程字符串拼接StringBuilder
多线程共享字符串对象StringBuffer
多线程 + 高性能要求StringBuilder + synchronized
不可变字符串(不修改)String

7. 结论

StringBuffer 是线程安全的,因为它的方法加了 synchronized,适用于多线程环境
StringBuilder 是线程不安全的,但性能更好,适用于单线程环境
线程安全不一定好,StringBuffer 虽然安全,但单线程下性能比 StringBuilder
如果多线程但又想提升性能,可以使用 StringBuilder + synchronized 进行手动控制

💡 面试高频考点

  1. StringBuffer 和 StringBuilder 的区别?
  2. 为什么 StringBuilder 是线程不安全的?
  3. 如何让 StringBuilder 变成线程安全的? ✅ 答案:加 synchronized,或者使用 Lock
  4. 什么时候用 StringBuffer?什么时候用 StringBuilder? ✅ 单线程用 StringBuilder,多线程用 StringBuffer

http://www.kler.cn/a/546811.html

相关文章:

  • C++实用技巧之 --- 观察者模式详解
  • OpenEuler学习笔记(三十三):在 OpenEuler 上搭建 OpenGauss 数据库环境
  • Swift 的 KeyPath 是什么?
  • Java网络编程学习(二)
  • 西门子S7-1500 PLC的自动化控制系统解决方案
  • 28 在可以控制 postgres 服务器, 不知道任何用户名的情况下怎 进入 postgres 服务器
  • 芯谷 D2761:专为扬声器保护设计的音频限幅器
  • maven-antrun-plugin插件的用法
  • 制造业物联网的十大用例
  • 国家队出手!DeepSeek上线国家超算互联网平台!
  • 探索DeepSeek:开源大模型领域的中国力量
  • Java中使用EasyExcel
  • 微信小程序日程预约
  • 【Python深入浅出㊵】解锁Python3的requests模块:网络请求的魔法钥匙
  • 遵循规则:利用大语言模型进行视频异常检测的推理
  • DeepSeek v3 技术报告阅读笔记
  • spring 中 AspectJ 基于 XML 的实现分析
  • 安全启动(secure boot)怎么关闭_史上最全的各品牌机和组装机关闭安全启动教程
  • 将错误消息输出到标准错误流:Rust中的最佳实践
  • web第三次作业