饿汉式
在类初始化时创建
可以保证多个线程下的唯一实例,getInstance()
的性能也比较高,但是无法进行懒加载
package com.example.demo.singleton;
public class SingletonDemo {
private static SingletonDemo instance = new SingletonDemo();
private SingletonDemo() {
}
public static SingletonDemo getInstance() {
return instance;
}
}
懒汉式
在使用类实例的时候再去创建
可以保证实例的懒加载,但无法保证单例的唯一性
package com.example.demo.singleton;
public class SingletonDemo {
private static SingletonDemo instance = null;
private SingletonDemo() {
}
public static SingletonDemo getInstance() {
if (null == instance) {
instance = new SingletonDemo();
}
return instance;
}
}
懒汉式+同步方法
既满足了懒加载也能够百分之百的保证instance
实例的唯一性,但是synchronized
关键字天生的排他性导致了getInstance
方法只能在同一时刻被一个线程所访问,性能低下
package com.example.demo.singleton;
public class SingletonDemo {
private static SingletonDemo instance = null;
private SingletonDemo() {
}
public static synchronized SingletonDemo getInstance() {
if (null == instance) {
instance = new SingletonDemo();
}
return instance;
}
}
Double-Check
提供了一种高效的数据同步策略,即在首次初始化时加锁,之后则允许多个线程同时进行getInstance
方法的调用来获得类的实例
多线程情况下可能会由于指令重排序问题引起空指针异常
package com.example.demo.singleton;
import java.net.Socket;
public class SingletonDemo {
private static SingletonDemo instance = null;
private Socket socket;
private SingletonDemo() {
this.socket = new Socket();
}
public static SingletonDemo getInstance() {
if (null == instance) {
synchronized (SingletonDemo.class) {
if (null == instance) {
instance = new SingletonDemo();
}
}
}
return instance;
}
public Socket getSocket() {
return socket;
}
}
Volatile + Double-Check
规避了指令重排序问题引起的空指针异常
满足多线程下的单例、懒加载以及获取实例的高效性
package com.example.demo.singleton;
import java.net.Socket;
public class SingletonDemo {
private volatile static SingletonDemo instance = null;
private Socket socket;
private SingletonDemo() {
this.socket = new Socket();
}
public static SingletonDemo getInstance() {
if (null == instance) {
synchronized (SingletonDemo.class) {
if (null == instance) {
instance = new SingletonDemo();
}
}
}
return instance;
}
public Socket getSocket() {
return socket;
}
}
Holder方式
在Singleton
类的初始化过程中并不会创建Singleton
的实例,Holder
类中定义了Singleton
的静态变量,并且直接进行了实例化,当Holder
被主动引用的时候则会创建Singleton
的实例,Singleton
实例的创建过程在Java程序编译时期收集至<clinit>()
方法中,该方法又是同步方法,同步方法可以保证内存的可见性、JVM指令的顺序性和原子性。
Holder
方式的单例设计是最好的设计之一,也是目前使用比较广的设计之一
package com.example.demo.singleton;
public class SingletonDemo {
private SingletonDemo() {
}
private static class Holder {
private static SingletonDemo instance = new SingletonDemo();
}
public static SingletonDemo getInstance() {
return Holder.instance;
}
}
枚举方式
线程安全
不能够懒加载,在调用其中的静态方法则INSTANCE会立刻得到实例化
package com.example.demo.singleton;
public enum SingletonDemo {
INSTANCE;
//实例变量
private byte[] data = new byte[1024];
SingletonDemo() {
System.out.println("INSTANCE will be initialized immediately");
}
public static void method() {
//调用该方法则会主动使用Singleton,INSTANCE将会被实例化
}
public static SingletonDemo getInstance() {
return INSTANCE;
}
}
懒加载改造
package com.example.demo.singleton;
public class SingletonDemo {
//实例变量
private byte[] data = new byte[1024];
private SingletonDemo() {
}
private enum EnumHolder {
INSTANCE;
private SingletonDemo instance;
EnumHolder() {
this.instance = new SingletonDemo();
}
private SingletonDemo getInstance() {
return instance;
}
}
public static SingletonDemo getInstance() {
return EnumHolder.INSTANCE.getInstance();
}
}