Java中String对象天然线程安全,根本原因在于其不可变性:内部字符数组为private final,所有“修改”操作均返回新对象,无写操作故无竞态条件,支持安全共享与JVM优化。

Java 中 String 对象在多线程环境下天然线程安全,根本原因不是靠加锁或同步机制,而是因为它不可变——内容一旦创建就再也无法被修改。
不可变性是线程安全的根源
String 内部用 private final char[](JDK 8)或 private final byte[](JDK 9+)存储字符数据,字段本身不可重赋值,数组内容也无法通过任何 public 方法更改。所有看似“修改”的操作,如 concat()、replace()、substring(),都返回一个全新对象,原对象状态恒定不变。
- 多个线程同时读取同一个 String 实例,看到的内容始终一致,不存在内存可见性问题
- 没有写操作,自然就没有竞态条件(Race Condition)
- 静态常量
public static final String DB_URL = "jdbc:mysql://host:3306/db"可被任意数量线程直接引用,无需synchronized或volatile
作为共享数据载体更可靠
String 常用于跨线程传递配置项、日志消息、HTTP 路径、数据库连接串等关键信息。不可变性确保这些值在传递过程中不会被中途篡改。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 主线程传入
String token = "abc123"给工作线程,后者无法通过任何合法 API 修改该 token 的内容 - RPC 框架中用 String 传 traceId、tenantId,下游模块调用
toUpperCase()或trim(),只生成新副本,原始上下文不受影响 - Spring Security 的
Authentication中 username 字段为 String,避免被过滤器或日志组件意外覆盖
与 JVM 关键机制深度协同
不可变性支撑字符串常量池、哈希码缓存等底层优化,反过来又强化了多线程下的稳定性。
立即学习“Java免费学习笔记(深入)”;
- 常量池复用:
String a = "log"; String b = "log"→a == b为 true,两个线程访问的是同一内存地址,且内容绝对一致 - 哈希缓存:首次调用
hashCode()后结果被缓存,后续直接返回;若 String 可变,HashMap 中的 key 会“消失”,导致查找失败 - 类加载器依赖 String 表示类名,安全管理器基于 String 判断权限策略,不可变保障了运行时逻辑不被干扰
注意不可变性的实际边界
开发者需清楚,“不可变”针对的是对象内容和公开行为,而非技术上绝对不可触达。
- 反射仍可修改
value数组,但属于破坏 JVM 合规性的非法操作,生产环境严禁使用 -
new String("x")总是在堆中新建对象,不参与常量池复用;而字面量"x"才可能被池化 - 变量可重新赋值(
s = "new"),这只是改变引用指向,并非修改原对象

















