爪哇。多线程环境中对象的序列化
我有一个对象,其内部可变状态正在由一个或多个线程不断更新。该对象是同步的,目标是定期从另一个线程保存其状态(通过序列化):
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
的同步不使用固有锁,而是使用其他锁怎么办?
I have an object whose internal mutable state is being constantly updated by one or more threads. The object is synchronized, and the goal is to periodically save its state (via serialization) from yet another thread:
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;
}
}
Questions:
- Is serialization safe in this case?
- How does it work under the hood? That is to say, will the
ObjectOutputStream
performing the serialization block until no threads are any longer operating onCounter
? - What if
Counter
's synchronization doesn't use the intrinsic lock, but some other lock?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不。正如 @Tom Hawtin 所说,您需要执行自己的锁定,以确保在序列化对象时不会更改对象。
ObjectOutputStream
在底层不进行锁定。如果需要的话,由应用程序来执行此操作。然后,您的应用程序还需要使用其他锁来在序列化发生时锁定更新。
如果您要序列化的状态仅由一个具有两个字段的对象的状态组成,那么锁争用和粒度应该不是问题。但如果对象很复杂,那么锁争用很可能会出现问题,就像在不冒死锁风险的情况下获取锁的问题一样。这种情况需要仔细设计。
No. As @Tom Hawtin says, you will need to perform your own locking to ensure that the object(s) are not changed while you are serializing them.
ObjectOutputStream
does no locking under the hood. It is up to the application to do this, if it is necessary.Then your application will also need to use that other lock to lock out updates while serialization is happening.
If the state that you are serializing simply consists of the state of one object with two fields, then lock contention and granularity should not be a problem. But if the object(s) are complicated, then lock contention could well be problematic, as could the problem of acquiring the locks without risking deadlock. That scenario would require careful design.
每当需要修改类的序列化时,您都必须实现特殊的私有方法
void writeObject(ObjectOutputStream)
。ObjectOutputStream
使用此方法而不是默认算法。在您的情况下,您希望序列化与对象同步。因此,您所要做的就是将
synchronized
关键字添加到该方法中。您仍然可以使用默认实现defaultWriteObject
:Whenever it's necessary to modify the serialization of a class you have to implement the special private method
void writeObject(ObjectOutputStream)
. TheObjectOutputStream
uses this method instead of the default algorithm then.In your case you want the serialization to be synchronized with the object. So all you have to do is adding the
synchronized
keyword to the method. You can still use the default implementationdefaultWriteObject
:它不安全,但相对容易做到这一点:
正如您所注意到的,锁定的对象是任意的,因此序列化机制如何知道如何获取相关的锁。更糟糕的是,序列化和对象图的顺序也是相当任意的,因此任何锁定尝试通常都会导致死锁。即使使用上面的解决方案,您也在锁内执行复杂的操作,因此要小心死锁。
It's not safe, but it is relatively easy to make it so:
As you noticed, the object locked is arbitrary, so how would the serialisation mechnaism know how to obtain the relevant lock. Worse than that, the order of serialising and object graph is also quite arbitrary, so any attempt to lock would often lead to deadlocks. Even with the solution above, you are performing a complex operation within a lock, so be careful about deadlocks.