单例模式的六种实现方式

单例模式的六种实现方式

1、单例模式之饿汉式[可用]

//饿汉式实现单例模式
public class Hungry {

    private Hungry(){}

    private  static Hungry hungry = new Hungry();

    public static Hungry getHungry(){
        return hungry;
    }
}

优点:实现简单,类加载的时候就完成了实例化,避免了线程的同步问题
缺点:无法实现延迟加载,可能会造成内存的浪费(浪费可忽略)

2、单例模式之懒汉式[不可用]

//懒汉式实现单例模式
public class LazySingleton01 {

    private LazySingleton01(){}

    private static LazySingleton01 lazy ;

    public static LazySingleton01 getLazy(){
        if(lazy==null){
            return new LazySingleton01();
        }
        return lazy;
    }
}

缺点:线程不安全,不推荐使用

存在线程安全问题的过程:在运行过程中可能会存在这么一种情况,有多个线程去调用getLazy方法来获取LazySingleton01实例,就有可能发生,第一个线程在执行if(lazy = =null)的语句时,还没执行new LazySingleton01()时,第二个线程获得的lazy也为null,通过了(lazy==null)的判断,最终两个线程都会new实例。

3、单例模式之懒汉式+同步方法[不推荐使用]

//懒汉式+同步方法实现单例模式
public class LazySingleton02 {
    private LazySingleton02(){}

    private static LazySingleton02 lazy;

    public static synchronized LazySingleton02 getLazy(){
        if(lazy==null){
            return new LazySingleton02();
        }
        return lazy;
    }
}

线程安全,效率低不推荐使用

对于上述缺陷的改进可能有的人会想到如下的代码:

public class LazySingleton03 {
    private LazySingleton03(){}

    private static LazySingleton03 lazy;

    public static  LazySingleton03 getLazy(){
        if(lazy==null){
        	synchronized(LazySingleton03.class){
            	return new LazySingleton03();
            }
        }
        return lazy;
    }
}

该写法一样是线程不安全的,当一个线程还没有实例化LazySingleton03时,另一个线程执行到if(lazy==null)这个判断语句时就会进入if语句,虽然加了锁,但是等到第一个线程执行完lazy=new LazySingleton03()释放出这个锁时,另一个进入if语句的线程同样会实例化另外一个LazySingleton03对象。

经过一步步的探索,有了双重校验锁的懒汉式写法:

4、单例模式之懒汉式+双重校验锁[推荐使用]

//双重校验锁+懒汉式
public class DoubleCheckSingleton {
    private DoubleCheckSingleton(){}
    
    private volatile static DoubleCheckSingleton instance;
    
    public static DoubleCheckSingleton getInstance(){
        if(instance==null){
            synchronized (DoubleCheckSingleton.class){
                if(instance==null){
                    return new DoubleCheckSingleton();
                }
            }
        }
        return instance;
    }
}

优点:线程安全,延迟加载,效率较高

注意此处的volatile:

//双重校验锁+懒汉式
public class DoubleCheckSingleton {
    private Socket socket;

    private DoubleCheckSingleton(){
        this.socket=new Socket();
    }
    
    private volatile static DoubleCheckSingleton instance;
    public static DoubleCheckSingleton getInstance(){
        if(instance==null){
            synchronized (DoubleCheckSingleton.class){
                if(instance==null){
                    return new DoubleCheckSingleton();
                }
            }
        }
        return instance;
    }
}

根据JVM运行时指令重排序和Happens-Before的规则,instance和socket之间的实例化的顺序并没有什么关系约束,谁在前谁在后都有可能,如果instance最先实例化,那么socket就不会实例化,调用这个方法就会产生空指针异常------>

解决这个方法很简单,加一个关键字 volatite
这个关键字能够保证实例化的顺序的相对位置不变,instance实例化永远在socket之后

5、单例模式之静态内部类[推荐使用]

//静态内部类实现单例模式
public class StaticInner {

    private StaticInner(){}

    private static class inner{
        private static StaticInner instance=new StaticInner();
    }

    public static StaticInner getInstance(){
        return inner.instance;
    }
}

优点:避免了线程不安全,延迟加载,效率高
详解:这个方法并没有事先声明instance的静态成员,而是把它放到了静态内部类inner中,inner中定义了静态变量,并直接进行了实例化,当inner被主动引用的时候就会创建实例,StaticInner在实例创建过程中被收集到()方法中,这个方法是同步方法,
保证了内存的可见性,JVM指令的顺序执行和原子性。该方法也是单例模式的最好设计之一。

6、单例模式之枚举[推荐使用]

//枚举实现单例模式
public enum EnumSingleton {
    INSTANCE;

    private EnumSingleton(){}

    public void method(){}
}

借助JDK1.5中添加的枚举来实现单例模式
优点:不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,实现非常简单而且最安全可谓很完美。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值