首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 序列化鎖競爭深度剖析:ObjectStreamClass.processQueue 全局鎖成性能殺手

     編輯:Java 相關知識

延續上文壓測,本文通過 Thread dump 與 JProfiler 數據,定位序列化性能崩潰的根因:java.io.ObjectStreamClass.processQueue() 內部調用 ReferenceQueue.poll() 時持有全局鎖,導致高併發下線程大面積阻塞。

Thread dump 關鍵堆棧

"testthread21" RUNNABLE
  at java.io.ObjectStreamClass.processQueue(Unknown Source)
  at java.io.ObjectStreamClass.lookup(Unknown Source)
  at java.io.ObjectOutputStream.writeObject0(Unknown Source)
  ...

"testthread49" BLOCKED (waiting for monitor entry)
  at java.lang.ref.ReferenceQueue.poll(Unknown Source)
  - waiting to lock <0x02fb1d40> (a java.lang.ref.ReferenceQueue$Lock)
  at java.io.ObjectStreamClass.processQueue(Unknown Source)
  ...

源碼級分析

// ObjectStreamClass.processQueue
static void processQueue(ReferenceQueue<Class<?>> queue, ConcurrentMap<...> map) {
    Reference<? extends Class<?>> ref;
    while ((ref = queue.poll()) != null) {  // ← poll() 內部 synchronized(lock)
        map.remove(ref);
    }
}

// ReferenceQueue.poll
public Reference<? extends T> poll() {
    if (queueEmpty) return null;
    synchronized (lock) {       // ← 全局鎖
        return reallyPoll();    // 極快
    }
}

Profile 數據量化

線程數lookup 累計時間佔比poll 方法耗時佔比
157.9%7.59%
257.85%9.47%
567.7%51.33%
5095.24%77.62%

隨線程數增加,poll 等待鎖時間佔比從 7% 飆升至 77%,reallyPoll 本身極快(微秒級),但排隊等待將整體吞吐拉低。

核心結論

  1. Java 序列化為 **CPU 密集型**,高度依賴單線程序列化速度。
  2. ObjectStreamClass 內部 **全局同步鎖** 成為擴展性瓶頸,線程越多競爭越烈,吞吐反降。
  3. 每序列化一個包含 1000 子對象的對象,需獲取/釋放鎖 2000 次,放大鎖開銷。

工程對策

  • 避免熱路徑大對象序列化:改用 Protobuf、Kryo、Avro 等高效二進制協議。
  • 若必須用 JDK 序列化:單線程序列化 + 異步隊列、對象池複用 ObjectOutputStream(線程不安全需加鎖)、實現 Externalizable 手工控制寫入邏輯減少反射。
  • JDK 9+ 已優化 ObjectStreamClass 使用 ConcurrentReferenceHashMap 降低鎖粒度,建議升級運行時。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved