java中的Singleton类

我正在思考编写单例类的其他方法。 那么这个class级被认为是一个单身人士class级吗?

public class MyClass{ static Myclass myclass; static { myclass = new MyClass();} private MyClass(){} public static MyClass getInstance() { return myclass; } } 

因为静态块只运行一次。

不它不是。 您没有声明myClass private static finalgetInstance()也不是static 。 代码也没有真正编译。

这是单身人士的习语:

 public class MyClass { private static final MyClass myClass = new MyClass(); private MyClass() {} public static MyClass getInstance() { return myClass; } } 

它应该是private ,以便其他人无法直接访问它。 它应该是static因此它只有一个。 它应该是final以便它不能被重新分配。 您还需要在声明期间直接实例化它,这样您就不必担心(那么多)线程。

如果加载是昂贵的,你因此更喜欢延迟加载Singleton,那么考虑Singleton holder习惯用法,它根据需要而不是在类加载期间进行初始化:

 public class MyClass { private MyClass() {} private static class LazyHolder { private static final MyClass myClass = new MyClass(); } public static MyClass getInstance() { return LazyHolder.myClass; } } 

但是,无论你是否需要单身人士,都应该提出大问号。 通常不需要它。 只是静态变量,枚举,工厂类和/或dependency injection通常是更好的选择。

这是另一种方法:

 public enum Singleton{ INSTANCE("xyz", 123); // Attributes private String str; private int i; // Constructor Singleton(String str, int i){ this.str = str; this.i = i; } } 

根据Josh Bloch的Effective Java,这是在Java中实现Singleton的最佳方法。 与涉及私有静态实例字段的实现不同,私有静态实例字段可以通过滥用reflection和/或序列化进行多次实例化,枚举可以保证是单例。

枚举单例的主要限制是它们总是在类加载时实例化,不能被懒惰地实例化。 因此,例如,如果要使用运行时参数实例化单例,则必须使用不同的实现(最好使用双重检查锁定)。

我就是这样做的。 它更快,因为它只在创建实例时需要synchronized块。

 public class MyClass { private static MyClass INSTANCE=null; private MyClass() { } public static MyClass getInstance() { if(INSTANCE==null) { synchronized(MyClass.class) { if(INSATCNE==null) INSTANCE=new MyClass(); } } return INSTANCE; } } 

使用您的示例并使用GoF的实现方式:

 public class MyClass{ private static Myclass instance; private MyClass(){ //Private instantiation } public static synchronized MyClass getInstance() //If you want your method thread safe... { if (instance == null) { instance = new MyClass(); } return instance; } } 

希望这可以帮助:

有三种方法可以在java中创建单例。

  1. 急切的初始化单身人士

     public class Test { private static final Test test = new Test(); private Test() { } public static Test getTest() { return test; } } 
  2. 懒惰初始化单例(线程安全)

     public class Test { private static volatile Test test; private Test(){} public static Test getTest() { if(test == null) { synchronized(Test.class) { if(test == null){test = new Test();} } } return test; } } 
  3. Bill Pugh Singleton带有Holder Pattern(最好是最好的)

     public class Test { private Test(){} private static class TestHolder { private static final Test test = new Test(); } public static Test getInstance() { return TestHolder.test; } } 

你的class级(原始代码,编辑前):

 public class MyClass { Myclass myclass; static { myclass = new MyClass();} private MyClass(){} public MyClass getInstance() { return myclass; } } 

不是一个真正的单身人士:

  1. 字段myclass不是私有的,可以从外部读取和更改(假设你有一个实现它的实例)
  2. 字段myclass不是静态的,无法在静态构造函数中访问(编译错误)
  3. getInstance()方法不是静态的,因此您需要一个实例来调用它

实际代码:

 public class MyClass { static Myclass myclass; static { myclass = new MyClass();} private MyClass(){} public static MyClass getInstance() { return myclass; } } 

仍然有myclass不是私人的(也不是最终的)…宣布它是最终的将有助于防止它从课堂内无意中改变。

 private static final Myclass myclass; 
 public class singletonPattern { private static singletonPattern obj; public static singletonPattern getObject() { return obj = (obj == null) ? new singletonPattern() : obj; } public static void main(String args[]) { singletonPattern sng = singletonPattern.getObject(); } } 

这个游戏可能会有点晚,但基本实现看起来像这样:

 public class MySingleton { private static MySingleton INSTANCE; public static MySingleton getInstance() { if (INSTANCE == null) { INSTANCE = new MySingleton(); } return INSTANCE; } ... } 

这里我们有MySingleton类,它有一个名为INSTANCE的私有静态成员,以及一个名为getInstance()的公共静态方法。 第一次调用getInstance()时,INSTANCE成员为null。 然后,流将进入创建条件并创建MySingleton类的新实例。 对getInstance()的后续调用将发现已经设置了INSTANCE变量,因此不会创建另一个MySingleton实例。 这确保了只有一个MySingleton实例在getInstance()的所有调用者之间共享。

但是这个实现有一个问题。 multithreading应用程序将在创建单个实例时具有竞争条件。 如果多个执行线程在同一时间(或大约)同时命中了getInstance()方法,则每个执行线程都会将INSTANCE成员视为null。 这将导致每个线程创建一个新的MySingleton实例,然后设置INSTANCE成员。


 private static MySingleton INSTANCE; public static synchronized MySingleton getInstance() { if (INSTANCE == null) { INSTANCE = new MySingleton(); } return INSTANCE; } 

这里我们使用方法签名中的synchronized关键字来同步getInstance()方法。 这肯定会解决我们的竞争状况。 线程现在将阻止并一次输入一个方法。 但它也会产生性能问题。 此实现不仅同步单个实例的创建,还将所有调用同步到getInstance(),包括读取。 读取不需要同步,因为它们只返回INSTANCE的值。 由于读取将占我们调用的大部分(请记住,实例化仅在第一次调用时发生),我们将通过同步整个方法而导致不必要的性能损失。


 private static MySingleton INSTANCE; public static MySingleton getInstance() { if (INSTANCE == null) { synchronize(MySingleton.class) { INSTANCE = new MySingleton(); } } return INSTANCE; } 

在这里,我们将同步从方法签名移动到包装MySingleton实例创建的同步块。 但这能解决我们的问题吗? 好吧,我们不再阻止阅读,但我们也向前退了一步。 多个线程将同时或大约同时命中getInstance()方法,并且它们都将INSTANCE成员视为null。 然后,他们将点击同步块,其中一个将获得锁并创建实例。 当该线程退出该块时,其他线程将争用该锁,并且每个线程将逐个通过该块并创建该类的新实例。 所以我们回到了我们开始的地方。


 private static MySingleton INSTANCE; public static MySingleton getInstance() { if (INSTANCE == null) { synchronized(MySingleton.class) { if (INSTANCE == null) { INSTANCE = createInstance(); } } } return INSTANCE; } 

在这里,我们从INSIDE块发出另一张支票。 如果已经设置了INSTANCE成员,我们将跳过初始化。 这称为双重检查锁定。

这解决了我们的多实例化问题。 但是,我们的解决方案又一次提出了另一项挑战。 其他线程可能不会“看到”INSTANCE成员已更新。 这是因为Java优化了内存操作。 线程将变量的原始值从主存储器复制到CPU的缓存中。 然后,将对值的更改写入该缓存并从中读取。 这是Java的一项function,旨在优化性能。 但这给我们的单例实现带来了问题。 第二个线程 – 由不同的CPU或核心使用不同的缓存处理 – 将不会看到第一个线程所做的更改。 这将导致第二个线程将INSTANCE成员视为null,从而强制创建我们的单例的新实例。


 private static volatile MySingleton INSTANCE; public static MySingleton getInstance() { if (INSTANCE == null) { synchronized(MySingleton.class) { if (INSTANCE == null) { INSTANCE = createInstance(); } } } return INSTANCE; } 

我们通过在INSTANCE成员的声明中使用volatile关键字来解决这个问题。 这将告诉编译器始终读取和写入主内存,而不是CPU缓存。

但这种简单的改变需要付出代价。 因为我们绕过CPU缓存,所以每次操作易失性INSTANCE成员时我们都会受到性能影响 – 我们会这样做4次。 我们仔细检查存在(1和2),设置值(3),然后返回值(4)。 有人可能会争辩说这条路径是边缘情况,因为我们只在第一次调用方法时创建实例。 也许创作的表现可以容忍。 但即使是我们的主要用例read也会对volatile组件进行两次操作。 一旦检查存在,再次返回其值。


 private static volatile MySingleton INSTANCE; public static MySingleton getInstance() { MySingleton result = INSTANCE; if (result == null) { synchronized(MySingleton.class) { result = INSTANCE; if (result == null) { INSTANCE = result = createInstance(); } } } return result; } 

由于性能影响是由于直接在volatile成员上运行,让我们将局部变量设置为volatile的值,然后对局部变量进行操作。 这将减少我们对易失性操作的次数,从而回收我们失去的一些性能。 请注意,当我们进入synchronized块时,我们必须再次设置本地变量。 这可确保它在我们等待锁定时发生的任何更改都是最新的。

我最近写了一篇关于此的文章。 解构单身人士 。 您可以在这些示例中找到更多信息,并在那里找到“持有者”模式的示例。 还有一个真实的例子展示了双重检查的volatile方法。 希望这可以帮助。

Singloton类是每次都获得相同对象的类。 当你想限制一个类创建多个对象时,我们需要Singleton类。

例如 :

 public class Booking { static Booking b = new Booking(); private Booking() { } static Booking createObject() { return b; } } 

要创建此类的对象,我们可以使用:

 Booking b1, b2, b3, b4; b1 = Booking.createObject(); b2 = Booking.createObject(); Booking b1, b2, b3, b4; b1 = Booking.createObject(); b2 = Booking.createObject(); 

b1b2指的是同一个对象。

在创建单例类时,您应该考虑以下属性

  1. reflection
  2. multithreading
  3. 克隆
  4. 序列化

如果您的类中没有Clone或Serialization接口,我认为以下类最适合作为单例类。

 public class JavaClass1 { private static JavaClass1 instance = null; private JavaClass1() { System.out.println("Creating -------"); if (instance != null) { // For Reflection throw new RuntimeException("Cannot create, please use getInstance()"); } } public static JavaClass1 getInstance() { if (instance == null) { createInstance(); } return instance; } private static synchronized void createInstance() { // for multithreading if (instance == null) { instance = new JavaClass1(); } }}