从线程内部修改外部对象

Modify outer object from inside a thread

public void fooAndBar() {
    HashMap<Foo, Bar> fooBarMap = new HashMap<>();
    CompletionService completionService = new ExecutorCompletionService(exec);

    for(int i=0; i<10; i++) {
        completionService.submit(new Callable() {
            @Override
            public Void call() throws Exception {
                fooBarMap.put(new Foo(i), new Bar(i));
                return null;
            }
        });
    }
}

我正在努力掌握 java 概念,请多多包涵

Hashmap 不应是最终的,因为您要对其进行多次修改(在 for 循环中)。

如果将其设为最终版本,则可能会出错。

Is it safe to modify the HashMap inside the Callable?

没有。如果您使用的是线程池,我假设您计划并行使用更多这些可调用对象 运行。任何时候从多个线程访问具有可变状态的对象时,都是线程不安全的。如果同时从两个线程写入一个线程不安全的 hashmap,其内部结构将被破坏。如果您从一个线程不安全的 hashmap 中读取,而另一个线程正在同时写入它,您的读取线程将读取垃圾。这是一种众所周知且经过广泛研究的情况,称为 竞争条件 ,对此的描述完全超出了本答案的范围。有关详细信息,请阅读 Race Condition on Wikipedia or on another question answered back in 2008: Whosebug - What is a Race Condition

Should the hashmap be final (or maybe volatile) and if so, why?

为了您的目的,它不需要是最终的,但最好将任何可以成为最终的东西都设为最终。

不需要 volatile 因为:

  • 如果你要让它变成易变的,你会把它的引用变成易变的,但引用永远不会改变,改变的是它的内容,而易变与那些无关。

  • 线程池确保 call() 将在 fooBarMap = new HashMap<>() 之后执行。 (如果你想知道为什么这样的事情会成为一个问题,google for "memory boundary"。)

Should I use a structure other than HashMap, something like ConcurrentHashMap or SynchronizedMap and why?

当然。因为,正如我之前所写,任何时候从多个线程访问具有可变状态的对象时,都是线程不安全的。 ConcurrentHashMapSynchronizedMapsynchronize 等正是为了处理线程不安全的情况而存在的。