Java的。在多线程环境中序列化对象

时间:2010-06-20 00:06:19

标签: java serialization synchronization

我有一个对象,其内部可变状态由一个或多个线程不断更新。该对象是同步的,目标是定期从另一个线程中保存其状态(通过序列化):

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的同步不使用内部锁,而是使用其他锁?
  • ,该怎么办?

3 个答案:

答案 0 :(得分:3)

每当需要修改类的序列化时,您必须实现特殊的私有方法void writeObject(ObjectOutputStream)ObjectOutputStream使用此方法而不是默认算法。

在您的情况下,您希望序列化与对象同步。所以你要做的就是在方法中添加synchronized关键字。您仍然可以使用默认实现defaultWriteObject

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

答案 1 :(得分:2)

这不安全,但实现起来相对容易:

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

正如您所注意到的,锁定的对象是任意的,因此序列化机制如何知道如何获得相关的锁定。更糟糕的是,序列化和对象图的顺序也很随意,因此任何锁定尝试都会导致死锁。即使使用上面的解决方案,您也在锁内执行复杂操作,因此请注意死锁。

答案 2 :(得分:2)

  
      
  • 在这种情况下序列化安全吗?
  •   

没有。正如@Tom Hawtin所说,您需要执行自己的锁定,以确保在序列化对象时不会更改对象。

  
      
  • 它是如何在引擎盖下工作的?也就是说,ObjectOutputStream是否会执行序列化块直到没有线程再次在Counter上运行?
  •   

ObjectOutputStream没有锁定。如果有必要,由应用程序来完成。

  
      
  • 如果Counter的同步不使用内部锁定,而是使用其他锁定怎么办?
  •   

然后,您的应用程序还需要使用该其他锁来锁定更新,同时进行序列化。

如果您正在序列化的状态只包含一个具有两个字段的对象的状态,那么锁争用和粒度应该不是问题。但是如果对象很复杂,那么锁争用可能会成为问题,因为获取锁的问题可能没有死锁的风险。那种情况需要仔细设计。