Java的。 在multithreading环境中序列化对象

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

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

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

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

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

ObjectOutputStream没有锁定。 如果有必要,应由此应用程序执行此操作。

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

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

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

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

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

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

它不安全,但它是相对容易的:

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

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