2010-06-20 44 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(); 
}