Java ExecutorService的线程是否保证更新本地声明的并发hashmap? 公共无效测试(){ 列表整数=新的ArrayList(); 对于(int i=0;iintegers.parallelStream().forEach(integer->{ 字符串名称=Thread.currentThread().getName(); System.out.println(“Foo”+名称); cache.put(整数,整数); })).get(); }捕获(例外e){ } System.out.println(缓存); }

Java ExecutorService的线程是否保证更新本地声明的并发hashmap? 公共无效测试(){ 列表整数=新的ArrayList(); 对于(int i=0;iintegers.parallelStream().forEach(integer->{ 字符串名称=Thread.currentThread().getName(); System.out.println(“Foo”+名称); cache.put(整数,整数); })).get(); }捕获(例外e){ } System.out.println(缓存); },java,multithreading,java-8,java-stream,executorservice,Java,Multithreading,Java 8,Java Stream,Executorservice,我了解到,您需要使用volatile变量,以确保对变量的更新能够以可预测的方式传播到其他线程 在这个测试方法中,我不能将“cache”并发hashmap声明为“volatile”变量,因为它是一个局部变量而不是实例变量。当代码到达System.out.println(缓存)行时,是否可以保证我的主线程将看到ExecutorService线程添加到“缓存”中的所有值?是的,您的代码将正常工作。ConcurrentHashMap保证所有插入的映射都将以线程安全的方式发生 您不需要关心池和缓存——它们

我了解到,您需要使用volatile变量,以确保对变量的更新能够以可预测的方式传播到其他线程


在这个测试方法中,我不能将“cache”并发hashmap声明为“volatile”变量,因为它是一个局部变量而不是实例变量。当代码到达System.out.println(缓存)行时,是否可以保证我的主线程将看到ExecutorService线程添加到“缓存”中的所有值?

是的,您的代码将正常工作。
ConcurrentHashMap
保证所有插入的映射都将以线程安全的方式发生

您不需要关心
缓存
——它们实际上是最终变量,因此,它们的值一旦在构建时设置(在启动任何多线程代码之前)就不会再更改


可能会让您感到困惑的是,在处理非最终字段时,如果您打算更改它们,并且确保更改正确地跨线程传播,则可能需要将它们标记为
volatile
。但是如上所述,请注意在这种情况下,
pool
caches
的值从未改变。

我忽略了Java8的“有效最终”概念。对于那些感兴趣的人,这是我发现的一篇文章。此外,我还发现这篇文章解释了为什么final变量可以保证其他线程的可见性@这里不需要
final
变量的特殊保证。在启动任何异步操作之前,您正在初始化
缓存
,因此,无论您使用哪种类型的变量,该值对他们都是可见的。正如这个答案所说,只有在异步操作开始后更改变量,才能出现可见性问题。但是在这种情况下,您可能会遇到比可见性多得多的问题,因此即使不声明它
volatile
,也可以解决所有问题。@Holger我们不是在并发hashmap中写入新值吗。因此,我猜只有在我们重新分配时才需要最终保证?@howly背景线程启动后对地图所做的修改不受特殊最终字段保证的影响。它们可以工作,因为
ConcurrentHashMap
为并发更新提供了保证。对于一个普通的
HashMap
,这将不起作用,并且没有任何修改器添加到它的引用变量中可以改变它。明白了。谢谢
public void test() {

    List<Integer> integers = new ArrayList<>();
    for(int i = 0; i < 1000; i++) {
        integers.add(i);
    }

    Map<Integer, Integer> cache = new ConcurrentHashMap<>();
    ExecutorService pool = new ForkJoinPool(10);
    try {
        pool.submit(() -> integers.parallelStream().forEach(integer -> {
            String name = Thread.currentThread().getName();
            System.out.println("Foo " + name);
            cache.put(integer, integer);
        })).get();
    } catch (Exception e) {

    }

    System.out.println(cache);
}