-
singleton
2016-04-04 15:12:06singletonpulbic class Singleton { //Static variables are initialized only once when //the Classloader load the class for the first time. private static Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } }
上面代码就是单例模式最简单的实现方式,这种实现方式适合那些在初始化时就要用到单例的情况,这种方式简单粗暴,如果单例对象初始化非常快,而且占用内存非常小的时候这种方式是比较合适的,可以直接在应用启动时加载并初始化 —— Eager Instantiation
如果单例初始化的操作耗时比较长而应用对于启动速度又有要求,或者单例的占用内存比较大,再或者单例只是在某个特定场景的情况下才会被使用,而一般情况下是不会使用时,使用Eager Instantiation的单例模式就是不合适的,这时候就需要用到Lazy Instantiation的方式去按需延迟加载单例。如下代码:
pulbic class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (null == instance) { instance = new Singleton(); } return instance; } }
Eager Instantiation与Lazy Instantiation的最大区别就是将单例的初始化操作,延迟到需要的时候才进行,这样做在某些场合中有很大用处。比如某个单例用的次数不是很多,但是这个单例提供的功能又非常复杂,而且加载和初始化要消耗大量的资源,这个时候使用Lazy Instantiation就是非常不错的选择。
多线程下的单例模式
上面介绍了一些单例模式的基本应用方法,但是上面所说的那些使用方式都是有一个隐含的前提,那就是他们都是应用在单线程条件下,一旦换成了多线程就有出错的风险。
如果在多线程的情况下,Eager Instantiation不会出现问题,因为JVM只会加载一次单例类,但是Lazy Instantiation可能就会出现重复创建单例对象的问题。为什么会有这样的问题呢?因为Lazy Instantiation在创建单例时是线程不安全的,多个线程可能会并发调用他的 getInstance 方法导致多个线程可能会创建多份相同的单例出来。
那有没有办法,使Lazy Instantiation的单利模式也是线程安全的呢?答案肯定是有的,就是使用加同步锁的方式去实现。如下代码:pulbic class Singleton { private static Singleton instance; private Singleton() {} synchronized public static Singleton getInstance() { if (null == instance) { instance = new Singleton(); } return instance; } }
这种是最常见的解决同步问题的一种方式,使用同步锁 synchronized防止多线程同时进入造成instance被多次实例化。
有没有更好的实现方式呢?答案是肯定的。 我们可以利用JVM的类加载机制去实现。在很多情况下JVM已经为我们提供了同步控制,比如:在static{}区块中初始化的数据,访问final字段时等等。因为在JVM进行类加载的时候他会保证数据是同步的,我们可以这样实现:采用内部类,在这个内部类里面去创建对象实例。这样的话,只要应用中不使用内部类 JVM 就不会去加载这个单例类,也就不会创建单例对象,从而实现Lazy Instantiation的延迟加载和线程安全。如下代码:
静态内部类:pulbic class Singleton { //内部类,在加载该内部类是才会去创建单例对象 private static class SingletonHolder { public static Singleton instance = new new Singleton(); } private Singleton() {} public static Singleton getInstance() { return SingletonHolder.instance; } }
你真的会写单例模式吗——Java实现
singleton模式四种线程安全的实现Java Singleton and Synchronization
静态内部类什么时候加载呢?
加载一个类时,其内部类是否同时被加载?引申出单例模式的另一种实现方式
静态内部类、静态变量的加载次数-理解静态内部类实现线程安全的单例模式
When is a static nested class (and static members therein) loaded into memory?
when static variables are initialized in Java
How static class variables get initialized -
Singleton
2018-08-21 19:10:331. 单例模式的实现方式1: ... public class Singleton1 { ... private static final Singleton1 INSTANCE = new Singleton1(); private Singleton1() { } public static Singleton1 get...1. 单例模式的实现方式1:
package com.object;
public class Singleton1 {
private static final Singleton1 INSTANCE = new Singleton1();
private Singleton1() { }
public static Singleton1 getInstance() {
return INSTANCE;
}}
2. 单例模式的实现方式2:package com.object;
public class Singleton2 {
private static Singleton2 instance = null;
private Singleton2() { }
public static synchronized Singleton2 getInstance() {
if (instance == null) {
instance = new Singleton2();
}
return instance;
}}
3. 单例模式的实现方式3:
package com.object;
public class Singleton3 {
private static Singleton3 instance = null;
private Singleton3() { }
public static Singleton3 getInstance() {
if (instance == null) {
synchronized(Singleton3.class) {
if (instance == null) {
instance = new Singleton3();
}
}
}
return instance;
}}
4. 单例模式的实现方式4:
package com.object;
public class Singleton4 {
private static class SingletonHolder {
private static final Singleton4 INSTANCE = new Singleton4();
}private Singleton4() { }
public static Singleton4 getInstance() {
return SingletonHolder.INSTANCE;
}}