3

我一直在阅读“Effective Java”第 60条,即“支持使用标准异常”。

另一个值得了解的通用异常是 ConcurrentModificationException。如果设计用于单线程或具有外部同步的对象检测到它正在被同时修改,则应引发此异常。

通常,人们CME在循环时尝试从集合中删除时会遇到这种情况。

但是在这里,我对检测对自我实现的类对象的并发修改的简洁示例感兴趣?

我希望它类似于在内部对象和相关的布尔标志上同步,如果另一个线程遇到该标志为假,则抛出异常。

对于我在来源中发现的简单研究ArrayList

 final void checkForComodification() {
     if (modCount != expectedModCount)
         throw new ConcurrentModificationException();
 }

modCount但是如何保持背后的原则。我找不到它在哪里被递减。

4

3 回答 3

3

修改计数本质上是集合状态的“修订号”。每次对集合进行结构更改时,它都会增加。它永远不会递减。

开始迭代时,迭代器会记住 mod 计数的值。然后它会定期检查容器的当前 mod 计数是否仍然等于记住的值。如果没有 - 意味着自迭代开始以来已经发生了结构变化 - aConcurrentModificationException被抛出。

于 2013-03-29T13:00:48.447 回答
2

至于您将如何自己实现这种行为:您的类依赖于一些假设才能正常工作,如果对对象的访问未正确同步,则可能会违反这些假设。如果您发现它们不正确,请尝试检查这些假设并抛出 CME。

在 的示例中ArrayList,假设在您迭代列表时没有人会更改列表的结构,因此ArrayList跟踪在迭代期间不应更改的修改计数。

然而,这种检查只是为了让错误的访问更有可能导致干净的异常而不是奇怪的行为——换句话说,这个异常只是对开发人员的帮助,不需要强制执行正确性,因为正确性已经当你遇到它时妥协了。

在不会对类的性能产生太大影响的情况下提供这种帮助是一个好主意,但是使用例如同步来确保正确使用可能是一个坏主意——那么你不妨一开始就让类线程安全。

这就是为什么 API 文档ArrayList说:

请注意,不能保证迭代器的快速失败行为,因为一般来说,在存在不同步的并发修改的情况下,不可能做出任何硬保证。快速失败的迭代器会尽最大努力抛出 ConcurrentModificationException。因此,编写一个依赖于这个异常的正确性的程序是错误的:迭代器的快速失败行为应该只用于检测错误。

于 2013-03-29T13:21:24.160 回答
0

所以,一般的做法如下:只要记住对象的当前状态,每次尝试访问对象时检查它的状态,如果状态改变,抛出你的异常!

于 2013-03-29T13:21:28.573 回答