根据这篇文章,线程安全的单例类应该如下所示。但我想知道是否有必要将volatile
关键字添加到静态单例实例
变量中。因为如果实例被创建并存储在CPU缓存中,此时它不会写回主存,同时,另一个线程调用getInstance()
方法。它会引起不一致的问题吗?
public class CrunchifySingleton {
private static CrunchifySingleton instance = null;
protected CrunchifySingleton() {
}
// Lazy Initialization
public static CrunchifySingleton getInstance() {
if (instance == null) {
synchronized (CrunchifySingleton.class) {
if (instance == null) {
instance = new CrunchifySingleton();
}
}
}
return instance;
}
}
您如何引用它的代码在Java中是不完整的。是的,您需要volatile
和至少Java5才能使双重检查的习惯用法线程安全。您还应该在惰性初始化中添加一个局部变量以提高性能。请在此处阅读更多信息:https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
是的,如果你的Singleton实例不是易失性
,或者即使它是易失性
,但是你使用了足够旧的JVM,那么没有对行中的操作的排序保证
instance = new CrunchifySingleton();
根据易失性
存储进行分解。
然后,编译器可以对这些操作重新排序,使您的实例不为null(因为已分配内存),但仍然未初始化(因为尚未执行其构造函数)。
如果您想了解更多关于双重检查锁定的隐藏问题,特别是在Java中,请参阅“双重检查锁定被破坏”声明。
lazy holder习惯用法是一个很好的模式,可以很好地概括一般静态字段延迟加载,但是如果您需要一个安全简单的单例模式,我推荐Josh Bloch(来自Efficial Java fame)推荐的Java Enum单例:
public enum Elvis {
INSTANCE;
public void leaveTheBuilding() { ... }
}
我附和上面@duffymo的评论:懒惰的单身汉远没有他们最初看起来那么有用。
但是,如果必须使用惰性实例化的单例,那么惰性持有者习惯用法是实现线程安全性的一种更简单的方法:
public final class CrunchifySingleton {
private static class Holder {
private static final CrunchifySingleton INSTANCE = new CrunchifySingleton();
}
private CrunchifySingleton() {}
static CrunchifySingleton getInstance() { return Holder.INSTANCE; }
}
另外,请注意,要成为真正的单例,类需要禁止实例化和子类化-构造函数需要是私有的
,类需要分别是最终的
。
volatile的写操作,无法保证线程安全。例如假如线程1,线程2 在进行read,load 操作中,发现主内存中count的值都是5,那么都会加载这个最新的值,在线程1对count进行修改之后,会write到主内存中,主内存中的count变量就会变为6;线程2由于已经进行read,load操作,在进行运算之后,也会更新主内存count的变量值为6;导致两个线程及时用volatile关键字修改之后,还是会存在并发的情况。
本文向大家介绍java枚举是如何保证线程安全的,包括了java枚举是如何保证线程安全的的使用技巧和注意事项,需要的朋友参考一下 前言 写在前面:Java SE5提供了一种新的类型-Java的枚举类型,关键字enum可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用,这是一种非常有用的功能。本文将深入分析枚举的源码,看一看枚举是怎么实现的,他是如何保证线程安全的
问题内容: 有关Singletons的维基百科文章提到了一些用线程安全的方法来用Java实现结构。对于我的问题,让我们考虑具有冗长的初始化过程并且一次被多个线程访问的Singleton。 首先,这个未提及的方法是线程安全的吗?如果是的话,它在什么上进行同步? 其次,为什么以下实现线程安全且在初始化时是懒惰的?如果两个线程同时进入该方法,到底会发生什么? 最后,在第二个示例中,如果一个线程首先获取一
最近我在读一些关于java并发的书。关于线程安全,如果不可能使一个类变为inmutable,那么可以通过同步它的数据来确保线程安全。 下面的类显然不是线程安全的 然后我可以同步写,但它不会保持线程安全 因为我不仅需要同步写入,还需要同步读取 现在的问题是,通过使用易失性,我可以保证其他线程会看到更新的值,所以这让我认为这个类应该是线程安全的 最后一个类线程安全吗??
问题内容: 我需要在性能关键的环境中使用MessageDigest对来自多个线程的多个键进行哈希处理。我知道MessageDigest不是线程安全的,因为它在其对象中存储其状态。什么是实现密钥的线程安全哈希的最佳方法? 用例: 特别: ThreadLocal是否可以保证正常工作?它会有性能损失吗? getInstance返回的对象是否不同,并且它们不会互相干扰?文档说“新”对象,但是我不确定它是否
我注意到,implements在JavaScript中是一个保留关键字。然而,我还没有发现该关键字的任何用法。事实上,我知道JavaScript中没有接口的概念,这与Java等其他编程语言不同,Java在实现接口时使用