从线程内部修改外部对象

时间:2017-04-17 07:51:42

标签: java multithreading java-threads

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;
            }
        });
    }
}
  • Callable内修改HashMap是否安全?

  • hashmap应该是final(或者volatile),如果是,为什么?

  • 我应该使用HashMap以外的结构,例如ConcurrentHashMapSynchronizedMap以及为什么?

我试图掌握java概念所以请耐心等待我

2 个答案:

答案 0 :(得分:2)

  

在Callable中修改HashMap是否安全?

没有。如果您正在使用线程池,我假设您计划让更多的这些callables并行运行。每当从多个线程访问具有可变状态的对象时,该线程就不安全了。如果同时从两个线程写入线程不安全的hashmap,其内部结构将被破坏。如果你从一个线程不安全的hashmap读取而另一个线程同时写入它,你的读取线程将读取垃圾。这是一个众所周知且广泛研究的情况,称为种族条件,其描述完全超出了本答案的范围。有关详情,请参阅Race Condition on Wikipedia或2008年回答的其他问题:Stackoverflow - What is a Race Condition

  

hashmap应该是final(或者可能是volatile),如果是,为什么?

为了您的目的,它不需要是最终的,但最终做出可以最终决定的任何事情总是一个好习惯。

它不需要是volatile,因为:

  • 如果你要使它变得不稳定,你就会将它的引用变为volatile,但是引用永远不会改变,它的内容会发生变化,而volatile与它们无关。

  • 线程池确保在{/ em> call()之后将执行fooBarMap = new HashMap<>()。 (如果你想知道为什么这样的事情可能会成为一个问题,谷歌为#34;内存边界&#34;。)

  

我应该使用HashMap以外的结构,比如ConcurrentHashMap或SynchronizedMap,为什么?

当然。因为,正如我之前所写,每当从多个线程访问具有可变状态的对象时,该线程就不安全了。 ConcurrentHashMapSynchronizedMapsynchronize等正是为了解决线程不安全的情况而存在的。

答案 1 :(得分:-4)

Hashmap不应该是最终的,因为你要多次修改它(从for循环中)。

如果你做到最后,你可能会收到错误。