| 維度 | transient | volatile |
| 所屬領域 | 對象序列化/持久化 | 多線程內存可見性/指令重排 |
| 作用目標 | 實例字段(不參與序列化) | 實例/靜態字段(主內存讀寫) |
| 核心語義 | 「此字段不持久化/不傳輸」 | 「每次讀寫直達主內存,禁止緩存/重排」 |
| 典型場景 | 密碼、Logger、衍生字段 | 狀態標誌、雙重檢查鎖、單例 DCL |
| JVM 層面 | ObjectOutputStream 跳過該字段 | 內存屏障、緩存一致性協議(MESI) |
transient 正確用法回顧
class User implements Serializable {
private String name;
private transient String password; // 序列化時忽略,反序列化後為 null
private transient Logger log; // 非串行化資源
}
- 序列化:
password、log 不寫入字節流。
- 反序列化:兩字段自動賦默認值(null)。
- 需在
readObject 中手動恢復(如重建 Logger、解密密碼)。
volatile 正確語義(補充)
volatile 保證:可見性(寫入立即刷新主內存,讀取立即從主內存讀取)+ 有序性(禁止指令重排優化)。不保證原子性(如 volatile int i; i++ 仍非線程安全)。
經典適用場景:狀態標誌
class TaskRunner {
private volatile boolean stopped = false; // 線程 A 修改,線程 B 可見
public void run() {
while (!stopped) { doWork(); }
}
public void stop() { stopped = true; }
}
雙重檢查鎖 (DCL) 單例
public class Singleton {
private static volatile Singleton instance; // 禁止指令重排:分配內存 → 初始化 → 賦值
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) instance = new Singleton();
}
}
return instance;
}
}
為什麼會混淆?
- 名稱相似:都以
trans 開頭,英文單詞皆為「短暫/揮發」含義。
- 早期技術博客轉載鏈條中,有人誤將
volatile 代碼/註釋貼在 transient 文章下,被大量複製傳播。
- 部分教材未對比講解,導致初學者混淆。
記憶錨點
- transient → serialization(序列化):
trans = transfer/transmit 傳輸時跳過。
- volatile → visibility(可見性):
volatile → volatile memory(易揮發內存)→ 每次直達主存。
源碼級驗證
HashMap.modCount (transient)
transient int modCount; // 結構修改計數,反序列化歸零合理
CopyOnWriteArrayList (volatile)
private volatile Object[] array; // 寫入新數組引用,讀線程立即可見
總結
transient = 序列化開關;volatile = 並發可見性開關。 兩者解決完全不同領域的問題,切勿混淆。遇到「不想序列化」用 transient;遇到「多線程共享變量可見性」用 volatile(或更高級的 Atomic*/Lock)。技術傳播中,請以官方規範(JLS、JVM Spec)為準,拒絕二手轉載誤導。
- 上一篇文章: Java transient 關鍵字深度解析:序列化控制、實戰場景與 HashMap 源碼案例
- 下一篇文章: Windows 下 Java 環境變量配置與 Tomcat 9 安裝圖文教程
Copyright ©
程式碼之家 All Rights Reserved