爪哇。多线程环境中对象的序列化

发布于 2024-09-06 11:23:06 字数 598 浏览 3 评论 0原文

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

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 on Counter?
  • What if Counter's synchronization doesn't use the intrinsic lock, but some other lock?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

挽容 2024-09-13 11:23:06
  • 在这种情况下序列化安全吗?

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

  • 它的底层是如何工作的?也就是说,ObjectOutputStream 执行序列化是否会阻塞,直到没有线程再在 Counter 上操作?

ObjectOutputStream 在底层不进行锁定。如果需要的话,由应用程序来执行此操作。

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

然后,您的应用程序还需要使用其他锁来在序列化发生时锁定更新。

如果您要序列化的状态仅由一个具有两个字段的对象的状态组成,那么锁争用和粒度应该不是问题。但如果对象很复杂,那么锁争用很可能会出现问题,就像在不冒死锁风险的情况下获取锁的问题一样。这种情况需要仔细设计。

  • Is serialization safe in this case?

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.

  • 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 on Counter?

ObjectOutputStream does no locking under the hood. It is up to the application to do this, if it is necessary.

  • What if Counter's synchronization doesn't use the intrinsic lock, but some other lock?

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.

风尘浪孓 2024-09-13 11:23:06

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

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

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

Whenever it's necessary to modify the serialization of a class you have to implement the special private method void writeObject(ObjectOutputStream). The ObjectOutputStream 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 implementation defaultWriteObject:

private synchronized void writeObject(ObjectOutputStream out) throws IOException {
    out.defaultWriteObject();
}
九命猫 2024-09-13 11:23:06

它不安全,但相对容易做到这一点:

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

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

It's not safe, but it is relatively easy to make it so:

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文