Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/387.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java哈希表大小()后跟值(),线程中是否安全?_Java_Multithreading_Thread Safety_Hashtable - Fatal编程技术网

Java哈希表大小()后跟值(),线程中是否安全?

Java哈希表大小()后跟值(),线程中是否安全?,java,multithreading,thread-safety,hashtable,Java,Multithreading,Thread Safety,Hashtable,我在一个线程中按顺序执行以下操作: int size=hashTable.size() foreach。。。。在里面hasTable.values() 做点什么 我的问题是,foreach是否会执行大小倍?(即使另一个线程同时放置/删除一个元素?如果另一个线程在foreach执行期间修改哈希表,那么您的代码将抛出ConcurrentModificationException否,在方法级别上线程是安全的(多个线程可以随时调用任何方法)但是没有跨方法的同步。在两条指令之间,其他线程可能会添加/删除甚

我在一个线程中按顺序执行以下操作:

int size=hashTable.size()

foreach。。。。在里面hasTable.values()

做点什么


我的问题是,foreach是否会执行大小倍?(即使另一个线程同时放置/删除一个元素?

如果另一个线程在foreach执行期间修改
哈希表,那么您的代码将抛出
ConcurrentModificationException
否,在方法级别上线程是安全的(多个线程可以随时调用任何方法)但是没有跨方法的同步。在两条指令之间,其他线程可能会添加/删除甚至清除哈希表

如果需要保持这种不变,请创建一个防御性副本(不必是线程安全的),并在该副本上执行
size()
/循环:

Map<K, V> map = null;
synchronized(hashTable) {
  map = new java.util.HashMap<>(hashTable);
}
map.size();
for(V v: map.values()) {
  //...
}
但是,此解决方案意味着一次只能有一个线程执行循环(如果循环需要一些时间才能完成,则这可能成为瓶颈)。使用防御副本,每个线程都有自己的副本,多个线程可以同时循环。另一方面,如果
哈希表
非常大,则此解决方案会更好(复制成本很高)但迭代非常快

Java哈希表大小()后跟值(),线程中是否安全

因此,不安全的不是
values()
方法调用。而是在
values()
上打开一个迭代器,该迭代器由
HashTable
支持。如果在迭代过程中对表进行了修改,则迭代器会引发异常

我的问题是,foreach会被执行大小倍吗?(即使另一个线程同时放置/移除一个元素

如前所述,
哈希表
如果在迭代时被修改,将抛出异常

HashTable
几乎已被弃用。如果您正在寻找一个现代的并发版本的
HashMap
,那么您应该使用Java 5中添加的版本。
ConcurrentHashMap
正确地处理在后台进行迭代时发生修改的情况,而无需额外的同步或cop莹:

ConcurrentHashMap<...> map = new ConcurrentHashMap<...>();
int size = map.size();
for (... value : map.values()) {
    // may be called more or less than size if other threads add or delete
    ...
}
ConcurrentHashMap=新的ConcurrentHashMap();
int size=map.size();
对于(…值:map.values()){
//如果其他线程添加或删除,则可能称为大于或小于大小
...
}

您的示例不是线程安全的,但可以很容易地使其成为线程安全的,如下所示:

synchronized(hashTable) {
  int size = hashTable.size();
  foreach.... in ... hasTable.values() {
    // do something
  }
}

这里有一个微妙之处。你将需要在
哈希表上
同步
,同时将其传递到
哈希表中
哈希表将在哈希表上迭代,这仍然会导致ConcurrentModificationException。也就是说,+1表示防御复制的想法。@JohnVint:+1,谢谢,你是对的!代码现在更难看了,但还是正确的。您觉得使用
hashTable.clone()怎么样
相反?为什么要复制,为什么不将两个操作都包装在一个同步块中?@jtahlborn这个答案取决于我得到的单个迭代的成本,但如果你说我需要通过哈希表进行同步来进行复制。这会使线程安全吗?如果我使用同步(哈希表)这会阻止在其他线程中访问hasTable的方法?所以,如果是这样,我还不足以执行此同步(hashTable){int size=hashTable.size();foreach….in…hasTable.values()do something}
synchronized(hashTable) {
  int size = hashTable.size();
  foreach.... in ... hasTable.values() {
    // do something
  }
}