在 Java 中,“不可变(Immutable)”通常意味着线程安全,但二者并不是完全等价的概念。下面分层说明。
一个对象在创建之后,其状态(字段值)不能被修改,就是不可变对象。
StringInteger、Long 等包装类BigDecimalfinal class + final 字段 + 不暴露修改方法public final class User {
private final String name;
private final int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
}
✅ 字段是 final
✅ 没有 setter
✅ 不返回可变对象的引用(或返回副本)
不可变对象可以被多个线程“安全共享”,无需
synchronized或volatile
这是《Java 并发编程实战》中的经典结论:
不可变对象永远是线程安全的
public final class BadExample {
private final List<String> list;
public BadExample(List<String> list) {
this.list = list; // 外部仍可修改
}
public List<String> getList() {
return list; // 暴露可变对象
}
}
❌ 虽然类是 final
❌ 字段是 final
❌ 但 List 是可变的 → 不线程安全
✅ 正确做法:
this.list = new ArrayList<>(list); // 防御性拷贝
或返回不可变集合:
return Collections.unmodifiableList(list);
public class Unsafe {
public Unsafe() {
Thread t = new Thread(() -> {
System.out.println(this.value);
});
t.start();
}
}
即使对象后来不变,构造过程也可能被其他线程看到不完整状态。
不可变对象本身安全,但对“引用”的更新不是原子的(除非 volatile 或 AtomicReference)。
config = new Config(); // 多线程下读取可能看到旧值
✅ 解决方案:
private volatile Config config;
或
AtomicReference<Config> config;
线程安全的实现方式不止“不可变”:
| 方式 | 示例 |
|---|---|
| 不可变 | String |
| 同步 | Vector, Hashtable |
| 无锁 | ConcurrentHashMap |
| 线程封闭 | ThreadLocal |
| 原子变量 | AtomicInteger |
✅ 不可变对象天然线程安全(前提是真正不可变)
⚠️ 不可变 ≠ 无需考虑共享引用的安全性
⚠️ 线程安全的方式有很多种,不可变只是最安全、最简单的一种
如果你愿意,我也可以:
String 为什么设计成不可变免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。