java Java中单例的其他方式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2111768/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 19:31:07  来源:igfitidea点击:

Other Ways of Singleton in Java

javadesign-patternssingleton

提问by GuruKulki

Just i was thinking about the other ways of writing singleton class. So is this class considered as a singleton class?

只是我在考虑编写单例类的其他方法。那么这个类是否被视为单例类?

      public class MyClass{
            static Myclass myclass;

            static { myclass = new MyClass();}

            private MyClass(){}

            public static MyClass getInstance()
            { 
                return myclass;
            }
       }

as the static block run only once.

因为静态块只运行一次。

回答by BalusC

No, it is not. You didn't declare myClassprivate static final, nor the getInstance()is static. The code also doesn't really compile.

不它不是。你没有申报myClassprivate static final,也不getInstance()static。代码也没有真正编译。

Here's the Singletonidiom:

这是单身人士的习惯用法:

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

    private MyClass() {}

    public static MyClass getInstance() {
        return myClass; 
    }
}

It should be private, so that nobody else can access it directly. It should be staticso that there's only one of it. It should be finalso that it cannot be reassigned. You also need to instantiate it directlyduring declaration so that you don't need to worry (that much) about threading.

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

If the loading is expensive and you thus rather prefer lazy loading of the Singleton, then consider the Singleton holderidiom which does initialization on demand instead of during classloading:

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

public class MyClass {
    private MyClass() {}

    private static class LazyHolder {
        private static final MyClass myClass = new MyClass();
    }

    public static MyClass getInstance() {
        return LazyHolder.myClass;
    }
}

You should however put big question marks whether you need a Singletonor not. Often it's not needed. Justa static variable, an enum, a factory class and/or dependency injection is often the better choice.

但是,无论是否需要单例,您都应该打上大大的问号。很多时候是不需要的。只是一个静态变量、一个枚举、一个工厂类和/或依赖注入通常是更好的选择。

回答by missingfaktor

Here's one more way to do it :

这是另一种方法:

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;
  }
}

According to Josh Bloch's Effective Java, this is the best way to implement Singleton in Java. Unlike implementations that involve a private static instance field, which can be multiply instantiated through the abuse of reflection and/or serialization, the enum is guaranteed to be a singleton.

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

The main limitation with enum singletons is that they are always instantiated at class loading time and can't be lazily instantiated. So if, for example, you want to instantiate a singleton using run-time arguments, you'll have to use a different implementation (preferably using double-checked locking).

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

回答by Dheeraj Sachan

There are 3 ways to create a singleton in java.

在 java 中创建单例有 3 种方法。

  1. eager initialization singleton

    public class Test {
        private static final Test TEST = new Test();
    
        private Test() {
        }
    
        public static Test getTest() {
            return TEST;
        }
    }
    
  2. lazy initialization singleton (thread safe)

    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 with Holder Pattern (Preferably the best one)

    public class Test {
        private Test(){}
    
        private static class TestHolder {
            private static final Test TEST = new Test();
        }
    
        public static Test getInstance() {
            return TestHolder.TEST;
        }
    }
    
  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 with 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;
        }
    }
    

回答by Pierre

Here is how I do it. It is faster, because it only requires a synchronizedblock when the instance is created.

这是我如何做到的。它更快,因为它只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;
    }
}

回答by user85421

Your class (original code, before editing):

您的课程(原始代码,编辑前):

public class MyClass {
    Myclass myclass;

    static { myclass = new MyClass();}

    private MyClass(){}

    public MyClass getInstance()
    {
        return myclass;
    }
}

is not a real singleton:

不是真正的单身人士:

  1. the field myclassis not private, can be read and changed from outside (assuming you got an instace to do it on
  2. the field myclassis not static, can not be accessed in the static constructor (compilation error)
  3. the getInstance()method is not static, so you need an instance to call it
  1. 该字段myclass不是私有的,可以从外部读取和更改(假设您有一个实例来执行此操作
  2. 该字段myclass不是静态的,无法在静态构造函数中访问(编译错误)
  3. getInstance()方法不是静态的,因此您需要一个实例来调用它


The actual code:


实际代码:

public class MyClass {
    static Myclass myclass;

    static { myclass = new MyClass();}

    private MyClass(){}

    public static MyClass getInstance()
    {
        return myclass;
    }
}

still has myclassnot being private (nor final)... declaring it final would help to prevent it being unintentionallychanged from inside the class.

仍然myclass不是私有的(也不是最终的)......声明它最终将有助于防止它在类内部被无意地更改。

private static final Myclass myclass;

回答by Buhake Sindi

Using your example and using the GoF's way of implementing it:

使用您的示例并使用 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;
    }
}

Hope this helps:

希望这可以帮助:

回答by Samet ?ZTOPRAK

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();
    }
}

回答by Michael Andrews

Might be a little late to the game on this, but a basic implementation would look something like this:

在这方面可能有点晚了,但基本的实现看起来像这样:

public class MySingleton {

     private static MySingleton INSTANCE;

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

        return INSTANCE;
    }
    ...
}

Here we have the MySingleton class which has a private static member called INSTANCE, and a public static method called getInstance(). The first time getInstance() is called, the INSTANCE member is null. The flow will then fall into the creation condition and create a new instance of the MySingleton class. Subsequent calls to getInstance() will find that the INSTANCE variable is already set, and therefore not create another MySingleton instance. This ensures there is only one instance of MySingleton which is shared among all callers of getInstance().

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

But this implementation has a problem. Multi-threaded applications will have a race condition on the creation of the single instance. If multiple threads of execution hit the getInstance() method at (or around) the same time, they will each see the INSTANCE member as null. This will result in each thread creating a new MySingleton instance and subsequently setting the INSTANCE member.

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



private static MySingleton INSTANCE;

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

    return INSTANCE;
}

Here we've used the synchronized keyword in the method signature to synchronize the getInstance() method. This will certainly fix our race condition. Threads will now block and enter the method one at a time. But it also creates a performance problem. Not only does this implementation synchronize the creation of the single instance, it synchronizes all calls to getInstance(), including reads. Reads do not need to be synchronized as they simply return the value of INSTANCE. Since reads will make up the bulk of our calls (remember, instantiation only happens on the first call), we will incur an unnecessary performance hit by synchronizing the entire method.

这里我们在方法签名中使用了 synchronized 关键字来同步 getInstance() 方法。这肯定会解决我们的竞争条件。线程现在将阻塞并一次进入一个方法。但它也带来了性能问题。这个实现不仅同步了单个实例的创建,它还同步了对 getInstance() 的所有调用,包括读取。读取不需要同步,因为它们只返回 INSTANCE 的值。由于读取将构成我们调用的大部分(请记住,实例化仅在第一次调用时发生),因此同步整个方法会导致不必要的性能下降。



private static MySingleton INSTANCE;

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

    return INSTANCE;
}

Here we've moved synchronization from the method signature, to a synchronized block that wraps the creation of the MySingleton instance. But does this solve our problem? Well, we are no longer blocking on reads, but we've also taken a step backward. Multiple threads will hit the getInstance() method at or around the same time and they will all see the INSTANCE member as null. They will then hit the synchronized block where one will obtain the lock and create the instance. When that thread exits the block, the other threads will contend for the lock, and one by one each thread will fall through the block and create a new instance of our class. So we are right back where we started.

在这里,我们将同步从方法签名移到了包装 MySingleton 实例创建的同步块。但这能解决我们的问题吗?好吧,我们不再阻塞读取,但我们也倒退了一步。多个线程将同时或大约同时命中 getInstance() 方法,并且它们都会将 INSTANCE 成员视为空。然后他们将点击同步块,在那里获得锁并创建实例。当该线程退出块时,其他线程将争夺锁,每个线程将一个接一个地穿过块并创建我们类的新实例。所以我们又回到了起点。



private static MySingleton INSTANCE;

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

    return INSTANCE;
}

Here we issue another check from INSIDE the block. If the INSTANCE member has already been set, we'll skip initialization. This is called double-checked locking.

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

This solves our problem of multiple instantiation. But once again, our solution has presented another challenge. Other threads might not “see” that the INSTANCE member has been updated. This is because of how Java optimizes memory operations. Threads copy the original values of variables from main memory into the CPU's cache. Changes to values are then written to, and read from, that cache. This is a feature of Java designed to optimize performance. But this creates a problem for our singleton implementation. A second thread?—?being processed by a different CPU or core, using a different cache?—?will not see the changes made by the first. This will cause the second thread to see the INSTANCE member as null forcing a new instance of our singleton to be created.

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



private static volatile MySingleton INSTANCE;

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

    return INSTANCE;
}

We solve this by using the volatile keyword on the declaration of the INSTANCE member. This will tell the compiler to always read from, and write to, main memory, and not the CPU cache.

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

But this simple change comes at a cost. Because we are bypassing the CPU cache, we will take a performance hit each time we operate on the volatile INSTANCE member?—?which we do 4 times. We double-check existence (1 and 2), set the value (3), and then return the value (4). One could argue that this path is the fringe case as we only create the instance during the first call of the method. Perhaps a performance hit on creation is tolerable. But even our main use-case, reads, will operate on the volatile member twice. Once to check existence, and again to return its value.

但这种简单的改变是有代价的。因为我们绕过了 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;
}

Since the performance hit is due to operating directly on the volatile member, let's set a local variable to the value of the volatile and operate on the local variable instead. This will decrease the number of times we operate on the volatile, thereby reclaiming some of our lost performance. Note that we have to set our local variable again when we enter the synchronized block. This ensures it is up to date with any changes that occured while we were waiting for the lock.

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

I wrote an article about this recently. Deconstructing The Singleton. You can find more info on these examples and an example of the "holder" pattern there. There is also a real-world example showcasing the double-checked volatile approach. Hope this helps.

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

回答by Sonali Mahajan

Singloton class is the class where you get the same object every time. When you want to restrict a class from creating more than one object the we need the Singleton Class.

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

For example :

例如 :

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

To create object of this class we can use :

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

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

b1and b2are referring to same object.

b1并且b2指的是同一个对象。

回答by Faiz Ahmed

You should think about the following properties while creating a singleton class

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

  1. Reflection
  2. Multi threading
  3. Clone
  4. Serialization
  1. 反射
  2. 多线程
  3. 克隆
  4. 序列化

if no Clone or Serialization interfaces in your class, i think the following class is best as singleton class.

如果您的课程中没有 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();
    }
}}