Singleton class in java
只是我在想单件课的其他写作方式。那么这个类被认为是单例类吗?
1 2 3 4 5 6 7 8 9 10 11 12 | public class MyClass{ static Myclass myclass; static { myclass = new MyClass();} private MyClass(){} public static MyClass getInstance() { return myclass; } } |
因为静态块只运行一次。
不,不是。你没有申报
以下是单例成语:
1 2 3 4 5 6 7 8 9 | public class MyClass { private static final MyClass myClass = new MyClass(); private MyClass() {} public static MyClass getInstance() { return myClass; } } |
应该是
如果加载很昂贵,因此您更喜欢单例加载的延迟加载,那么考虑单例持有者习惯用法,它根据需要进行初始化,而不是在类加载期间进行初始化:
1 2 3 4 5 6 7 8 9 10 11 | public class MyClass { private MyClass() {} private static class LazyHolder { private static final MyClass myClass = new MyClass(); } public static MyClass getInstance() { return LazyHolder.myClass; } } |
不过,你应该在是否需要单件衬衫上打上大问号。通常不需要。静态变量、枚举、工厂类和/或依赖注入通常是更好的选择。
还有一种方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
根据Josh Bloch的有效Java,这是在Java中实现Simelton的最好方法。与涉及私有静态实例字段的实现不同,该实例字段可以通过滥用反射和/或序列化进行多次实例化,枚举保证为单例。
枚举单例的主要限制是它们总是在类加载时被实例化,并且不能被延迟地实例化。因此,例如,如果您想使用运行时参数实例化一个单例,那么您必须使用不同的实现(最好使用双重检查锁定)。
我就是这样做的。它更快,因为创建实例时只需要一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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; } } |
1 2 3 4 5 6 7 8 9 10 11 | 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(); } } |
在Java中创建单体有3种方法。
热切初始化单例
1 2 3 4 5 6 7 8 9 10 | public class Test { private static final Test test = new Test(); private Test() { } public static Test getTest() { return test; } } |
惰性初始化单例(线程安全)
1 2 3 4 5 6 7 8 9 10 11 12 | 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; } } |
Bill Pugh单开门,带支架图案(最好是最好的)
1 2 3 4 5 6 7 8 9 10 11 | public class Test { private Test(){} private static class TestHolder { private static final Test test = new Test(); } public static Test getInstance() { return TestHolder.test; } } |
您的类(原始代码,编辑前):
1 2 3 4 5 6 7 8 9 10 11 12 | public class MyClass { Myclass myclass; static { myclass = new MyClass();} private MyClass(){} public MyClass getInstance() { return myclass; } } |
不是真正的单身汉:
< BR>实际代码:
1 2 3 4 5 6 7 8 9 10 11 12 | public class MyClass { static Myclass myclass; static { myclass = new MyClass();} private MyClass(){} public static MyClass getInstance() { return myclass; } } |
仍然有
1 | private static final Myclass myclass; |
使用您的示例并使用GOF的实现方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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; } } |
希望这有助于:
创建singleton类时,应该考虑以下属性
如果类中没有克隆或序列化接口,我认为下面的类最好是单例类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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(); } }} |
singloton类是每次获取相同对象的类。当您想限制一个类创建多个对象时,我们需要单例类。
例如:
1 2 3 4 5 | public class Booking { static Booking b = new Booking(); private Booking() { } static Booking createObject() { return b; } } |
要创建此类的对象,我们可以使用:
1 2 3 4 5 6 | Booking b1, b2, b3, b4; b1 = Booking.createObject(); b2 = Booking.createObject(); Booking b1, b2, b3, b4; b1 = Booking.createObject(); b2 = Booking.createObject(); |
在这一点上,可能有点晚了,但是一个基本的实现看起来是这样的:好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class MySingleton { private static MySingleton INSTANCE; public static MySingleton getInstance() { if (INSTANCE == null) { INSTANCE = new MySingleton(); } return INSTANCE; } ... } |
这里我们有mysingleton类,它有一个名为instance的私有静态成员,以及一个名为getInstance()的公共静态方法。第一次调用getInstance()时,实例成员为空。然后流将进入创建条件,并创建mysingleton类的新实例。对getInstance()的后续调用将发现实例变量已设置,因此不会创建另一个mysingleton实例。这样可以确保只有一个mysingleton实例在getInstance()的所有调用方之间共享。好的。
但是这个实现有一个问题。多线程应用程序在创建单个实例时将具有竞争条件。如果多个执行线程同时(或前后)命中getInstance()方法,它们将每个线程都将实例成员视为空。这将导致每个线程创建一个新的mysingleton实例,然后设置实例成员。好的。
1 2 3 4 5 6 7 8 9 | private static MySingleton INSTANCE; public static synchronized MySingleton getInstance() { if (INSTANCE == null) { INSTANCE = new MySingleton(); } return INSTANCE; } |
这里我们使用方法签名中的synchronized关键字来同步getInstance()方法。这肯定会改善我们的比赛条件。线程现在将一次阻塞并输入一个方法。但它也会造成性能问题。此实现不仅同步单个实例的创建,还同步对getInstance()的所有调用,包括读取。读取不需要同步,因为它们只返回实例的值。因为reads将占我们调用的大部分(记住,实例化只在第一个调用上发生),所以通过同步整个方法,我们将导致不必要的性能损失。好的。
1 2 3 4 5 6 7 8 9 10 11 | private static MySingleton INSTANCE; public static MySingleton getInstance() { if (INSTANCE == null) { synchronize(MySingleton.class) { INSTANCE = new MySingleton(); } } return INSTANCE; } |
在这里,我们将同步从方法签名移到了包装mysingleton实例创建的同步块。但这能解决我们的问题吗?好吧,我们不再阻止阅读,但我们也后退了一步。多个线程将同时或大约同时命中getInstance()方法,它们都将实例成员视为空。然后,它们将命中同步块,其中一个将获取锁并创建实例。当该线程退出该块时,其他线程将争夺该锁,并且每个线程将逐个通过该块并创建我们类的新实例。所以我们就回到了开始的地方。好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 | private static MySingleton INSTANCE; public static MySingleton getInstance() { if (INSTANCE == null) { synchronized(MySingleton.class) { if (INSTANCE == null) { INSTANCE = createInstance(); } } } return INSTANCE; } |
在这里,我们从街区内再开出一张支票。如果已经设置了实例成员,我们将跳过初始化。这叫做双重检查锁定。好的。
这就解决了多重实例化的问题。但我们的解决方案再一次提出了另一个挑战。其他线程可能看不到实例成员已被更新。这是因为Java如何优化内存操作。线程将变量的原始值从主内存复制到CPU的缓存中。然后,对值的更改将写入和读取该缓存。这是为优化性能而设计的Java特性。但这给我们的单例实现带来了一个问题。第二条线?-?由不同的CPU或核心处理,使用不同的缓存?-?将看不到第一个所做的更改。这将导致第二个线程将实例成员视为空,从而强制创建singleton的新实例。好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 | private static volatile MySingleton INSTANCE; public static MySingleton getInstance() { if (INSTANCE == null) { synchronized(MySingleton.class) { if (INSTANCE == null) { INSTANCE = createInstance(); } } } return INSTANCE; } |
我们通过在实例成员的声明中使用volatile关键字来解决这个问题。这将告诉编译器始终读取和写入主内存,而不是CPU缓存。好的。
但这种简单的改变是有代价的。因为我们绕过了CPU缓存,所以每次在易失性实例成员上操作时都会受到性能影响?-?我们做了4次。我们再次检查是否存在(1和2),设置值(3),然后返回值(4)。有人可能会说,这条路径是边缘情况,因为我们只在方法的第一次调用期间创建实例。也许对创作的影响是可以容忍的。但即使我们的主要用例reads也会对易失性成员进行两次操作。一次检查是否存在,再次返回其值。好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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; } |
由于性能下降是由于直接在易失性成员上操作造成的,所以让我们将局部变量设置为易失性的值,并改为在局部变量上操作。这将减少我们对易失性操作的次数,从而恢复一些丢失的性能。注意,当我们进入同步块时,必须再次设置本地变量。这样可以确保它是最新的,并且在等待锁时发生了任何更改。好的。
我最近写了一篇关于这个的文章。解构单重子。您可以在这里找到关于这些示例和"holder"模式的示例的更多信息。还有一个真实的例子展示了双重检查的易失性方法。希望这有帮助。好的。好啊。