一、饿汉式
此方式的关键在于instance作为类变量并且直接得到了初始化
public class SingletonObject1 {
private static final SingletonObject1 instance=new SingletonObject1();
public static SingletonObject1 getInstance(){
return instance;
}
}
缺点: 不能懒加载(占用内存)
二、懒汉式
懒汉式就是使用类实例的时候再去创建,避免出现类在初始化的时候提前创建
public class SingletonObject2 {
// 定义实例,但不进行初始化
private static SingletonObject2 intance;
public static SingletonObject2 getInstance(){
if (null==intance){
intance= new SingletonObject2();
}
return SingletonObject2.intance;
}
}
缺点: 懒汉式可以保证实例的懒加载,但是无法保证实例的唯一性。
三、懒汉式+同步方法
在多线程的情况下,多个线程同时访问instance(共享资源)需要保证数据的一致性,增加同步的约束。
public class SingletonObject3 {
// 定义实例,但不进行初始化
private static SingletonObject3 intance;
// 向getInstance方法加入同步控制,每次只能有一个线程能够进入
public synchronized static SingletonObject3 getInstance(){
if (null==intance){
intance= new SingletonObject3();
}
return SingletonObject3.intance;
}
}
缺点:尽管synchornized已经进行了优化,但是此关键字依旧导致getInstance方法只能在同一时刻被一个线程访问,降低了性能。
四、Double-Check
此种方式提供了一种高效的数据同步策略,就是首次初始化时加锁。
public class SingletonObject6 {
// 定义实例,但不进行初始化
private static SingletonObject6 instance;
public static SingletonObject6 getInstance(){
// 当instance为null的时候,进入代码块,同时判读那避免每次都需要进入同步代码块,可以提高效率
if (null==instance){
synchronized (SingletonObject6.class){
// 判断instance是否被创建
if(null==instance){
instance=new SingletonObject6();
}
}
}
return SingletonObject6.instance;
}
}
缺点:在多线程的情况下可能会引起空指针异常
五、volatile+Double-Check
加入volatile关键字防止jvm在运行时指令重排序
public class SingletonObject5 {
// 定义实例,但不进行初始化,加volatile使其对象可见
private volatile static SingletonObject5 instance;
public static SingletonObject5 getInstance(){
// 当instance为null的时候,进入代码块,同时判读那避免每次都需要进入同步代码块,可以提高效率
if (null==instance){
synchronized (SingletonObject5.class){
// 判断instance是否被创建
if(null==instance){
instance=new SingletonObject5();
}
}
}
return SingletonObject5.instance;
}
}
六、静态内部类的方式
借助类加载的特点,对单例进行重构。在Singleton类中没有instance的静态成员,而是将其放到了静态内部类中,以保证在Singleton类初始化过程中不会创建Singleton的实例,在静态内部类中定了singleton的静态变量,并且直接进行了初始化。
public class SingletonObject3 {
// 在静态内部类中吃有Singleton的实例,并且可以被直接初始化
private static class InstanceHolder{
private static SingletonObject3 instance=new SingletonObject3();
}
// 调用getInstance方法,事实上是获得静态内部类的instance静态属性
public static SingletonObject3 getInstance(){
return InstanceHolder.instance;
}
}
七、枚举的方式
推荐使用的一种方式,枚举类型不允许被继承,同样是线程安全的且只能被实例化一次,但是枚举类型不能进行懒加载,对Singleton主动使用。
public class SingletonObject4 {
// 枚举本身就是final的,不允许被继承
private enum EnumSingleton{
// 实例变量
INSTSNCE;
private SingletonObject4 instance;
EnumSingleton(){
this.instance=new SingletonObject4();
}
public SingletonObject4 getInstance(){
return instance;
}
}
public static SingletonObject4 getInstance(){
return EnumSingleton.INSTSNCE.getInstance();
}
}