我已经看到了SynchronizedList的用例-他们声明,在进行迭代时,即使SynchronizedList是线程安全的,我们也应该像这样使用迭代器和同步块-
synchronized(myList){
Iterator<Item> iterator = myList.iterator();
while (iterator.hasNext())
{
System.out.println(iterator.next().getMessage());
}
}
例如,如果我使用ConcurrentHashSet(在Java 8中可以使用并发HashMap的newKeySet()),那么在多线程环境中,是否仍然需要提取迭代器并使用同步块?我尝试对其进行测试,似乎没有必要,但是我可能会遗漏一些东西。
谢谢!
答案 0 :(得分:2)
据我所知-从ConcurrentHashMap获得的每个迭代器都设计为由单个线程使用,并且不应传递。
如果您尝试同时使用多个线程迭代Map,除非每个线程都使用自己的迭代器,否则它将无法按预期工作。
带有迭代器的ConcurrentHashMap的并发是指您要在迭代时尝试从映射中放置或删除值的情况-这样将是线程安全的。 尽管不能保证另一个线程会看到更改,除非它正在从映射中获取新的迭代器。
我希望这些信息有用!
答案 1 :(得分:1)
ConcurrentHashMap.newKeySet()
返回:
/**
* Creates a new {@link Set} backed by a ConcurrentHashMap
* from the given type to {@code Boolean.TRUE}.
*
* @param <K> the element type of the returned set
* @return the new set
* @since 1.8
*/
public static <K> KeySetView<K,Boolean> newKeySet() {
return new KeySetView<K,Boolean>
(new ConcurrentHashMap<K,Boolean>(), Boolean.TRUE);
}
如您所见,由ConcurrentHashMap支持。您可以使用返回的实例,而无需任何同步。
.iterator()
方法返回一个新的KeyIterator
,它由地图的Node<K,V>[] table
因此,如果您在一个特定的线程中进行迭代,这意味着您将看到Node
数组的快照,并且处于正确状态bc Node
的每个节点内部都有易失链接,但是您的机率最低将会看到添加到原始地图的新元素,因为链接迭代器点是可变的。换句话说,您只是遍历一个数组而没有任何保证,如果该元素仍然存在于原始map atm中或在其中添加了一些新元素,但是您可以看到每个节点的最新状态bc:
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
volatile V val;
volatile Node<K,V> next;
key
是最终的
val
易失