Java 迭代Set.toArray()返回的数组是否线程安全

Java 迭代Set.toArray()返回的数组是否线程安全,java,multithreading,Java,Multithreading,我有一个静态集合,用于缓存我的AType实例。多个Worker实例将在不同的线程上运行工作者将迭代此集合,根据每个类型的属性执行操作 (从不修改AType的属性。尽管集的内容本身可能会被修改) 如果我以线程安全的方式将集克隆到一个数组,那么迭代该数组是线程安全的吗 (我不明白为什么会这样。在我做的测试中,它似乎是安全的。但是线程安全性很难验证,问起来也没什么坏处……) 公共类工作者{ 私有AType[]可重用数组; 私有静态集theSet=newhashset(); 公职人员(){ //....

我有一个静态
集合
,用于缓存我的
AType
实例。多个
Worker
实例将在不同的线程上运行<代码>工作者将迭代此
集合
,根据每个
类型的属性执行操作

(从不修改
AType
的属性。尽管
集的内容本身可能会被修改)

如果我以线程安全的方式将
克隆到一个数组,那么迭代该数组是线程安全的吗

(我不明白为什么会这样。在我做的测试中,它似乎是安全的。但是线程安全性很难验证,问起来也没什么坏处……)

公共类工作者{
私有AType[]可重用数组;
私有静态集theSet=newhashset();
公职人员(){
//....
}
公共工程(){
//....
多克隆();
用于(AType AType:reusableArray){
// ...
}
}
私有void doClone(){
已同步(主题集){
//…做一些事情,可能填充集合,可能从集合中删除项目。
//除非必要,否则尽量不要调整数组大小
if(reusableArray==null | | reusableArray.length()!=theSet.size()){
reusableArray=新的AType[theSet.size()];
}
theSet.toArray(可重用阵列);
}
}
}

toArray
将集合的内容复制到数组中。返回后,数组和集合完全不相关

在第一个线程对
toArray
的调用返回后,您可以在同一个线程中修改集合,也可以在不同的线程中修改集合,可以让集合被垃圾收集,也可以将其启动到Jupiter。第一个线程不再使用该集合,它不关心它会发生什么


(请注意,存储在数组中的引用与存储在集合中的引用相同,因此它们引用相同的对象,更改这些对象可能会导致线程安全问题。但您说您没有这样做)

与其使用所有这些环,不如使用

或者,使用同步所有访问

建议第一选择,但各有利弊

基本上,
ConcurrentHashMap
在查询集合时不会锁定(
contains()
,迭代,…)。引用javadoc:

但是,即使所有操作都是线程安全的,检索操作也不需要锁定


注意:没有
ConcurrentHashSet
。要获取
集合
请按如下方式创建:

private static Set<AType> theSet = Collections.newSetFromMap(
                                     new ConcurrentHashMap<AType, Boolean>());
private static Set theSet=Collections.newSetFromMap(
新的ConcurrentHashMap());
瞧!快速、无阻塞的
设置
,仍然允许多线程访问,包括更新和查询

仅需注意(引用javadoc):

对于聚合操作,如
putAll
clear
,并发检索可能只反映插入或删除某些条目


这是我的逻辑。(也是为什么我提到我没有改变这些对象,因为我意识到这将是一个问题)。我想我最担心的是,如果集合被清空,数组的引用可能会被垃圾收集,尽管这似乎不太可能,因为我对数组的内容有硬引用。。。或者只是在编写多线程内容时一直担心/警告我遗漏了一些内容。@ab11你说得对。只有在集合和数组都超出范围后,才能对引用进行垃圾收集。如果这些收集在迭代期间锁定对象(我认为它们必须这样做,否则它们将如何避免并发修改问题),那么我将失去parellism的所有优势,因为大多数工作人员的时间都花在迭代期间执行逻辑上。@ab11正如我已经说过的,
ConcurrentHashMap
不会锁定。引用javadoc:“然而,即使所有操作都是线程安全的,检索操作也不需要锁定”。你自己读吧。这就是我提供链接的原因。谢谢,我读了链接。知道这是怎么回事吗?如果集合在迭代时被另一个线程修改,会发生什么情况?它可能会遍历集合的克隆?如果是这样,这是如何更有效的?如果你想知道他们是如何做到的,请阅读源代码。就我个人而言,我很高兴有一个非常聪明的人找到了一种方法,并给了我们代码。但是不,它不会克隆整个地图,而且比每次调用
work
时将集合“克隆”到数组中的代码要好。明白了。谢谢最后一件事,您是否看过任何说明newSetFromMap()将创建并发安全集的文档(如果参数是ConcurrentHashMap)?我查看了源代码,似乎它必须是并发安全的,因为它有ConcurrentHashMap的支持,但我没有看到任何文档说明这种情况。
private static Set<AType> theSet = Collections.newSetFromMap(
                                     new ConcurrentHashMap<AType, Boolean>());