这是线程安全的吗?

时间:2011-02-07 19:10:23

标签: java concurrency volatile

我想让我的类线程安全,没有大的开销。 实例很少会同时使用,但可能会发生。 大多数类都是不可变的,只有一个可变成员用作缓存:

private volatile SoftReference<Map<String, Something>> cache
    = new SoftReference(null);

在构造函数(未共享)中分配 ,如

Map<String, Something> tmp = new HashMap<String, Something>();
tmp.put("a", new Something("a");
tmp.put("b", new Something("b");
cache = new SoftReference(tmp);

分配后,地图永远不会被修改。

当两个线程并行计算缓存时,没有问题,因为值将是相同的。 单词完成两次的额外开销是可以接受的。

当一个线程看不到另一个花边计算的值时,它会计算它是不必要的,这是可以接受的。 这不会因为波动而发生。 当线程看到由另一个胎面计算的值时,它就没问题了。

唯一可能的问题是线程看到不一致的状态(例如部分填充的地图)。 这可能发生吗?

注意:

  1. 我真的希望轻柔地引用整个地图,这里使用软键或值的地图没用。

  2. 我知道ConcurrentHashMap并且可能会使用它,但我很好奇,如果使用volatile只能工作。

2 个答案:

答案 0 :(得分:4)

  

唯一可能的问题是a   线程看到不一致的状态(例如   部分填充的地图)。这会发生吗?

没有。必须执行在线程内执行的操作,就好像它们已按顺序执行一样。在读取该值之前,编写一个volatile变量。因此,地图的初始化发生在任何线程从字段读取对地图的引用之前。

答案 1 :(得分:1)

使用软引用的问题是您可能在GC之后丢失整个地图/缓存。这意味着您的应用程序的性能可能会非常困难。你最好使用带有驱逐策略的缓存,这样你就不会遇到这个问题。

此处的volatile不会使任何操作安全。

您尚未显示所有代码,也许我们可以提供一些有关如何改进代码的建议,例如:您的示例代码应该编译;)