2
    private static Map<Integer, String> map = null;

    public static String getString(int parameter){

        if(map == null){

            map = new HashMap<Integer, String>();
            //map gets filled here...

        }

        return map.get(parameter);
    }

随着多线程的发展,该代码是否不安全?

4

7 回答 7

4

如前所述,这绝对不安全。如果地图的内容不是基于 getString() 中的参数,那么最好将地图初始化为静态初始化程序,如下所示:

private static final Map<Integer, String> MAP = new HashMap<Integer,String>();

static {
  // Populate map here
}

加载类时,上面的代码被调用一次。它是完全线程安全的(尽管未来对地图的修改不是)。您是否出于性能原因尝试延迟加载它?如果是这样,这更安全:

private static Map<Integer, String> map = null;

public synchronized static String getString(int parameter){

    if(map == null){

        map = new HashMap<Integer, String>();
        //map gets filled here...

    }

    return map.get(parameter);
}

使用synchronized关键字将确保在任何时候只有一个线程可以执行该方法,并且始终传播对映射引用的更改。

如果你问这个问题,我推荐阅读“Java Concurrency in Practice”。

于 2013-03-05T21:45:25.627 回答
2

比赛条件?可能。

如果mapnull,并且两个线程if (map == null)同时检查,每个线程都会分配一个单独的映射。这可能是也可能不是问题,主要取决于是否map是不变的。即使地图是不变的,填充地图的成本也可能成为一个问题。

内存泄漏?不。

无论竞争条件如何,垃圾收集器都会正确完成其工作。

于 2013-03-05T21:24:18.710 回答
1

map在多线程场景中,您确实冒着初始化两次的风险。

在托管语言中,垃圾收集器最终将处理不再引用的实例。在非托管语言中,您永远不会释放为覆盖映射分配的内存。

无论哪种方式,初始化都应该得到适当的保护,以便多个线程不会同时运行初始化代码。

一个原因:第一个线程可能正在初始化 HashMap,而第二个线程很长,看到它map不为空,并愉快地尝试使用部分初始化的数据结构。

于 2013-03-05T21:22:06.687 回答
1

由于竞争条件,在多线程情况下它是不安全的。

但是你真的需要地图的延迟初始化吗?如果无论如何都要使用地图,似乎你可以为它做急切的初始化..

于 2013-03-05T21:36:35.937 回答
1

上面的代码不是线程安全的,正如其他人所提到的,您的地图可以初始化两次。您可能很想尝试通过添加一些同步来修复上述代码,这被称为“双重检查锁定”,这里有一篇文章描述了这种方法的问题,以及一些潜在的修复。

最简单的解决方案是使该字段成为单独类中的静态字段:

class HelperSingleton {
  static Helper singleton = new Helper();
 }

它也可以使用 volatile 关键字来修复,如 Bill Pugh 的文章中所述。

于 2013-03-05T21:41:50.443 回答
0

不,此代码对于多线程使用是不安全的。

在地图的初始化中存在竞争条件。例如,多个线程可以同时初始化映射并破坏彼此的写入。

没有内存屏障来确保线程所做的修改对其他线程可见。例如,每个线程都可以使用自己的映射副本,因为它们永远不会“看到”另一个线程写入的值。

没有原子性可以确保在同时访问映射时保留不变量。例如,一个正在执行get()操作的线程可能会进入无限循环,因为另一个线程在同时put()操作期间对存储桶进行了重新散列。

于 2013-03-05T21:47:48.940 回答
0

如果您使用的是 Java 6,请使用 ConcurrentHashMap

ConcurrentHashMap JavaDoc

于 2013-03-05T22:21:50.897 回答