【发布时间】:2019-03-07 13:20:33
【问题描述】:
在 Java 并发实践中作者给出了以下非线程安全类的示例,该类在后台调用 set 对象上的迭代器,如果涉及多个线程,这可能会导致 ConcurrentModificationException。这是可以理解的,一个线程正在修改集合,另一个线程正在对其进行迭代,然后 - 砰!
我不明白,-作者说可以通过用Collections.synchronizedSet() 包装HashSet 来修复此代码。这将如何解决问题?即使对所有方法的访问将被同一个内在锁同步和保护,但一旦获得迭代器对象,不能保证一旦进行迭代,其他线程就不会修改集合。
书中引用:
如果 HiddenIterator 用 synchronizedSet 包装了 HashSet,封装了同步,就不会出现这种错误。
public class HiddenIterator {
//Solution :
//If HiddenIterator wrapped the HashSet with a synchronizedSet, encapsulating the synchronization,
//this sort of error would not occur.
//@GuardedBy("this")
private final Set<Integer> set = new HashSet<Integer>();
public synchronized void add(Integer i) {
set.add(i);
}
public synchronized void remove(Integer i) {
set.remove(i);
}
public void addTenThings() {
Random r = new Random();
for (int i = 0; i < 10; i++)
add(r.nextInt());
/*The string concatenation gets turned by the compiler into a call to StringBuilder.append(Object),
* which in turn invokes the collection's toString method - and the implementation of toString in
* the standard collections iterates the collection and calls toString on each element to
* produce a nicely formatted representation of the collection's contents. */
System.out.println("DEBUG: added ten elements to " + set);
}
}
如果有人能帮助我理解这一点,我将不胜感激。
这是我认为可以修复的方法:
public class HiddenIterator {
private final Set<Integer> set = Collections.synchronizedSet(new HashSet<Integer>());
public void add(Integer i) {
set.add(i);
}
public void remove(Integer i) {
set.remove(i);
}
public void addTenThings() {
Random r = new Random();
for (int i = 0; i < 10; i++)
add(r.nextInt());
// synchronizing in set's intrinsic lock
synchronized(set) {
System.out.println("DEBUG: added ten elements to " + set);
}
}
}
或者,作为替代方案,可以为add() 和remove() 方法保留synchronized 关键字。在这种情况下,我们将在 this 上进行同步。此外,我们必须将一个同步块(再次在 this 上同步)添加到 addTenThings(),其中将包含一个操作 - 带有隐式迭代的日志记录:
public class HiddenIterator {
private final Set<Integer> set = new HashSet<Integer>();
public synchronized void add(Integer i) {
set.add(i);
}
public synchronized void remove(Integer i) {
set.remove(i);
}
public void addTenThings() {
Random r = new Random();
for (int i = 0; i < 10; i++)
add(r.nextInt());
synchronized(this) {
System.out.println("DEBUG: added ten elements to " + set);
}
}
}
【问题讨论】:
-
如果重复没有回答您的问题,请告诉我,我们会重新打开。
-
它没有回答这个问题。它不是重复的。请仔细阅读我的询问内容。
标签: java concurrency