【问题标题】:Taking lock to serialize取锁序列化
【发布时间】:2017-11-26 04:17:28
【问题描述】:

我是 Java 新手。 我正在通过编写小程序来练习。

在其中一个程序中,我有一个包含一些配置的对象。 可以在运行时更改此配置。 我通过序列化对象将配置保存到文件中。

在我看来,我必须在序列化之前锁定我正在序列化的对象,以确保它在序列化期间不会改变。

synchronized (myObject)
{
    output.writeObject(myObject);
} 

但是我读到应该尽量避免在同步块或任何其他形式的锁定下进行 IO 操作(例如写入文件)。这确实是有道理的,因为 IO 操作可能需要相对较长的时间,让其他线程等待/阻塞。

我想知道,是否有办法避免序列化被锁定... 欢迎提出任何建议。

【问题讨论】:

  • 您意识到仅靠同步块不会阻止并发修改,对吧?
  • @shmosel 我知道我需要确保 myObject 的所有修改都发生在同步块/方法中,以确保此同步块在序列化期间保护我。但很高兴你能确保我知道你,谢谢。
  • 我不同意你所读到的。在套接字编程中一直这样做。
  • @EJP 感谢您的评论。很高兴听到不同的意见,尤其是刚接触这门语言的人。

标签: java multithreading serialization io locking


【解决方案1】:

这个问题的几个解决方案是:

  1. 仅序列化不可变对象
  2. 创建对象的副本并序列化副本

【讨论】:

  • 感谢您的回答。在我的情况下,对象不是不可变的。我考虑过制作对象的副本。在我的情况下,对象很小,副本是相对“便宜”的选项。但是对于更大的对象(例如 List),这个解决方案在我看来成本很高。
【解决方案2】:

但是在设置对象和开始刷新它之间的时间间隔会发生什么?您仍然可以编写另一个对象。

一种可能的解决方案是在修改对象后锁定对象仅用于写入,并在刷新对象时首先解锁。锁定和解锁可以通过获取和释放binary semaphore来完成。

因此,acquire() 在写入对象变量之前获得许可,release 在序列化之后获得许可。这将仅阻止活动的 Modifier-threads 并有效地允许进一步的并发执行。这将避免您的示例中的 I/O 轮询。

一个问题是 Writer-thread 可能会有第二次上下文切换 - 在写完之后,就在释放锁之前。但是,如果您可以让 Modifier-thread(s) 再等待一段时间,那就不用担心了。

希望这会有所帮助!

【讨论】:

  • 首先,感谢您向我介绍 Semaphore 课程,还没有看到,读起来很有趣。
  • 我也喜欢你给线程起的名字,Modifiers 和 Writer,让讨论更容易。似乎即使使用 Semaphore 仍然存在一个问题 - Modifiers 阻塞,而 Writer 执行耗时的 IO 操作。我认为使用信号量的好处是,我们只影响那些等待特定信号量的块/方法,而不是影响所有同步块/方法。我没听错吗?
  • 是的,完全正确 - 只有那些必须这样做的人。
【解决方案3】:

您需要在 lock 内执行序列化过程,因为您的用例要求在写入期间任何人都不能修改。

1.基本的解决方案是通过使用transient关键字减少序列化的数据量来减少执行时间。此外,在某些情况下,自定义的 readObject() 和 writeObject() 方法可能会有所帮助。

2.如果可能的话,你可以修改你的逻辑,这样你就可以拆分你的锁,这样多个线程可以读取/但不能修改。

3.您可以在迭代可能需要很长时间的集合中使用类似 use 的模式,以便在迭代之前克隆原始对象。

【讨论】:

    猜你喜欢
    • 2015-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-13
    • 1970-01-01
    相关资源
    最近更新 更多