gpt4 book ai didi

Java 并发实践。 list 5.6

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:31:15 25 4
gpt4 key购买 nike

在 Java Concurrency in Practice 中,作者给出了以下非线程安全类的示例,它在后台调用 set 对象上的迭代器,如果涉及多个线程,这可能会导致 并发修改异常。这是可以理解的,一个线程正在修改集合,另一个线程正在迭代它,然后,- 砰!

我不明白的是,- 作者说这段代码可以通过用 Collections.synchronizedSet() 包装一个 HashSet 来修复。这将如何解决问题?即使对所有方法的访问都将同步并由同一个内部锁保护,一旦获得迭代器对象,就无法保证在进行迭代后其他线程不会修改集合。

书中引述:

If HiddenIterator wrapped the HashSet with a synchronizedSet, encapsulating the synchronization, this sort of error would not occur.

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 上进行同步。此外,我们必须将同步块(synchronized block)(再次在 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);
}
}
}

最佳答案

Collections.synchronizedSet() 将集合包装在名为 SynchronizedSet 的内部类实例中,扩展 SynchronizedCollection。现在让我们看看 SynchronizedCollection.toString() 是如何实现的:

public String toString() {
synchronized (mutex) {return c.toString();}
}

基本上迭代仍然存在,隐藏在 c.toString() 调用中,但它已经与此包装器集合的所有其他方法同步。因此您无需在代码中重复同步。

关于Java 并发实践。 list 5.6,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55044826/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com