2010-06-20 84 views
4

我有一個對象,其內部可變狀態不斷由一個或多個線程更新。對象是同步的,而我們的目標是定期從另一個線程保存(通過序列化)它的狀態:Java。多線程環境中的對象序列化

public class Counter implements Serializable { 
    private int dogCount; 
    private int catCount; 

    public synchronized void updateFromDogThread(int count) { 
     dogCount = count; 
    } 

    public synchronized void updateFromCatThread(int count) { 
     catCount = count; 
    } 
} 

問題:

  • 系列化是在這種情況下,安全嗎?
  • 它如何在引擎蓋下工作?也就是說,ObjectOutputStream將執行序列化塊,直到Counter沒有線程再運行爲止?
  • 如果Counter的同步沒有使用固有鎖定,但是其他鎖定會怎麼樣?

回答

2
  • 序列化在這種情況下是安全的嗎?

號作爲@湯姆Hawtin說,你需要執行自己的鎖定,以確保對象(S)沒有改變,而你是序列化他們。

  • 它是如何工作的?也就是說,ObjectOutputStream將執行序列化塊,直到沒有線程在計數器上運行爲止?

ObjectOutputStream沒有鎖定在引擎蓋下。如果有必要,這是由應用程序來完成的。

  • 如果計數器的同步不使用內部鎖,但一些其他的鎖呢?

那麼你的應用程序還需要使用其他的鎖鎖住了更新,同時序列化正在發生的事情。

如果您正在序列化的狀態只是由一個對象的狀態和兩個字段組成,那麼鎖定爭用和粒度不應該成爲問題。但是,如果對象複雜,那麼鎖定爭用可能會有問題,因爲獲取鎖的問題可能沒有死鎖風險。這種情況需要仔細的設計。

2

這不是安全的,但它是比較容易做起來很:

synchronized (counter) { 
    out.writeObject(counter); 
} 

正如你注意到,鎖定的對象是任意的,因此如何將序列化mechnaism知道如何獲得相關的鎖。更糟糕的是,序列化和對象圖的順序也是非常隨意的,所以任何鎖定的嘗試往往會導致死鎖。即使使用上述解決方案,您仍然在一個鎖中執行復雜的操作,因此請注意死鎖。

3

每當需要修改某個類的序列化時,必須執行特殊的私有方法void writeObject(ObjectOutputStream)ObjectOutputStream然後使用此方法而不是默認算法。

在你的情況下,你希望序列化與對象同步。因此,您只需將​​關鍵字添加到方法即可。您仍然可以使用默認實現defaultWriteObject

private synchronized void writeObject(ObjectOutputStream out) throws IOException { 
    out.defaultWriteObject(); 
}