我有一个 Java 应用程序,它有工作线程来处理作业。一个 worker 产生一个结果对象,比如:
class WorkerResult{
private final Set<ResultItems> items;
public Worker(Set<ResultItems> pItems){
items = pItems;
}
}
当 worker 完成后,它会执行以下操作:
...
final Set<ResultItems> items = new SomeNonThreadSafeSetImplSet<ResultItems>();
for(Item producedItem : ...){
items.add(item);
}
passToGatherThread(items);
items
集在这里是一种“工作单元”。 passToGatherThread
方法将 items
集传递给一个收集线程,其中只有一个在运行时存在。
这里不需要同步,因为竞争条件不会发生,因为只有一个线程(Gather-thread)读取items
集。 AFAICS,Gather-thread 可能看不到所有项目,因为集合不是线程安全的,对吗?
假设我不能使 passToGatherThread
同步,比如因为它是第 3 方库。我基本上担心的是,由于缓存、VM 优化等原因,收集线程看不到所有项目。所以问题来了:如何以线程安全的方式传递项目集,以便收集线程“看到”正确的项目集?
最佳答案
这里似乎没有同步问题。您为每个 passToGatherThread 创建一个新的 Set 对象,并在修改集合后执行。不会丢失任何对象。
集合(和大多数 Java 集合)可以被许多线程并发访问,前提是集合没有被修改。这就是 Collections.unmodifiableCollection
的用途。
由于提到的passToGatherThread
方法用作与其他线程的通信,它必须使用某种同步——并且每个同步确保线程之间的内存一致性。
此外 - 请注意,对传递的集合中的对象的所有写入都是在传递给其他线程之前进行的。即使内存被复制到线程的本地缓存中,它也具有与另一个线程中相同的未修改值。
关于Java线程安全地将集合对象从一个线程传递到另一个线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14812118/