Java 这个线安全吗?

Java 这个线安全吗?,java,concurrency,volatile,Java,Concurrency,Volatile,我想让我的类线程安全,而不会有很大的开销。 这些实例很少同时使用,但可能会发生。 类的大部分是不可变的,只有一个可变成员用作缓存: private volatile SoftReference<Map<String, Something>> cache = new SoftReference(null); 专用易失性软引用缓存 =新的软引用(空); 它在构造函数中被赋值(不是共享的),就像 Map tmp=newhashmap(); tmp.put(“a”),

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

private volatile SoftReference<Map<String, Something>> cache
    = new SoftReference(null);
专用易失性软引用缓存
=新的软引用(空);
它在构造函数中被赋值(不是共享的),就像

Map tmp=newhashmap();
tmp.put(“a”),新事物(“a”);
tmp.put(“b”),新事物(“b”);
缓存=新的软参考(tmp);
分配后,地图将永远不会被修改

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

当一个线程看不到由另一个踏板计算的值时,它会计算出不必要的值,这是可以接受的。 这种情况不会发生,因为它是不稳定的。 当一个线程看到由另一个踏板计算的值时,就可以了

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

笔记:
  • 我真的希望整个地图都被软引用,这里没有使用软键或值的地图

  • 我知道ConcurrentHashMap,也许无论如何都会使用它,但我很好奇,使用volatile是否只起作用

  • 唯一可能的问题是 线程看到不一致的状态(例如。 这会发生吗


    不可以。在线程内执行的操作必须按顺序执行。写入可变变量发生在读取该值之前。因此,映射初始化发生在任何线程从字段读取对映射的引用之前。

    使用软引用的问题是,您可能会丢失整个映射GC后映射/缓存。这意味着应用程序的性能可能会受到很大影响。最好使用带有逐出策略的缓存,这样就不会出现此问题


    挥发性物质不能保证这里的任何操作安全


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

    在哪里分配
    缓存
    。它是由线程共享的吗?不,它是在构造函数中完成的,不共享。这甚至不会编译。因此,如果您只读取软引用,它将是线程安全的,并且会在未命中时重新创建。我的意思是缓存=新的软引用(tmp),如果您确实需要在每个GetForget上检查它:我建议只初始化cache=new SoftReference(null);我知道ConcurrentHashMap,可能会使用它,但我很好奇,使用volatile是否有效。它确实有效;java.lang.Class以类似的方式缓存方法和字段(注意,当引用一次被清除时,你可能会得到所有的活动线程。你可能想尝试一些双重检查的恶作剧(但要小心)。@Peter,根据我的经验,SoftRef的性能确实不错,它们的预期寿命是基于可用的空闲堆(也有文档记录),与任何带有逐出策略的东西相比,它们几乎都是免费的。Sun也非常自由地使用它们。@bestsss,我同意开销很小。Sun倾向于将它们与替换成本不高的对象一起使用。您从缓存中获得的好处越多,删除它的成本就越高。这确实增加了代码的复杂性你必须检查各种空值,并根据需要重新创建哈希映射。“volatile不能使任何操作安全。”你说的“操作”是什么意思?你说的“安全”是什么意思?至少,volatile将保证缓存对其他线程可见。至于volatile在分配后,它确保CPU的其余部分可以看到缓存changes@Peter,imo N个线程可以重新创建缓存和转储的行为(通常)被认为是可以接受的,除非存在非常高的争用和所需的对象(缓存)是非常大的。那么您可能需要不允许这么多线程(在非常糟糕的线程调度之后,使用一个线程可能会导致饥饿)
    Map<String, Something> tmp = new HashMap<String, Something>();
    tmp.put("a", new Something("a");
    tmp.put("b", new Something("b");
    cache = new SoftReference(tmp);