[Java设计模式](二)单例模式

1、饿汉模式(可用)—线程安全

//饿汉模式
//在类加载时就完成了初始化,所以类加载较慢,但是获取对象的速度快
public class Singleton {
    //用静态变量来存储唯一实例
    private static final Singleton instance = new Singleton();
 
    //私有化构造函数
    private Singleton() {
        //里面可能有很多操作
        System.out.println("嘿嘿,我创建了呢!");
    }
 
    //提供一个公共的静态方法,用来返回唯一实例
    public static Singleton getInstance() {
        return instance;
    }
 
    public static void main(String[] args) {
        getInstance();
    }
}

饿汉模式的优缺点:

  1. 优点:由于使用了static 关键字,保证了在引用这个变量时,关于这个变量的所有写入操作都完成,即 类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变,所以保证了JVM层面的线程安全。
  2. 缺点:不能实现懒加载,造成空间浪费,如果一个类比较大,我们在初始化时就加载了这个类,但是我们长时间没有使用这个类,这就导致了内存空间的浪费。

2、懒汉模式(不可用)—线程不安全

public class Singleton {
    private static Singleton instance;
 
    private Singleton() {
 
    }
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

可能出现多份实例的情况。

3、懒汉模式(不推荐使用)—线程安全

public class Singleton {
    private static Singleton instance;
 
    private Singleton() {
 
    }
 
    public synchronized static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

经过修改后,解决了多份实例的问题,但是因为引入synchronized关键字,对代码加了锁,就引入了新的问题,加锁之后会使得程序变成串行话化,只有抢到锁的线程采取执行这段代码块,这会使得系统的性能大大下降。

懒汉模式的优缺点

  1. 优点:实现了懒加载,节约了内存空间。
  2. 缺点:在不加锁的情况下,线程不安全,可能出现多份实例;在加锁的情况下,会是程序串行化,使系统有严重的性能问题。

4、双重检查锁模式—线程不安全

public class Singleton {
    private static Singleton instance;
 
    private Singleton(){
    }
 
    public static Singleton getInstance(){
        if(instance==null){
            synchronized (Singleton.class){
                if(instance==null){
                    instance=new Singleton();
                }
            }
        }
        return instance;
    }
}

双重检查锁模式是一种非常好的单例实现模式,解决了单例,性能,线程安全问题,上面的双重检测锁模式看上去完美无缺,其实是存在问题,在多线程的情况下,可能会出现空指针问题,出现问题的原因是 JVM在实例化对象的时候会进行优化和指令重排序操作。

要解决双重检查锁模式带来空指针异常的问题,只需要使用volatile关键字,volatile关键字严格遵循happens-before原则,即在读操作前,写操作必须全部完成。添加volatile关键字之后的单例模式代码:

5、双重检查锁模式—线程安全

public class Singleton {
    private volatile static Singleton instance;
 
    private Singleton(){
    }
 
    public static Singleton getInstance(){
        if(instance==null){
            synchronized (Singleton.class){
                if(instance==null){
                    instance=new Singleton();
                }
            }
        }
        return instance;
    }
}

添加volatile关键字之后的双重检查锁模式是一种比较好的单例实现模式,能够保证在多线程的情况下线程安全也不会有性能问题。

6、静态内部类模式—线程安全

静态内部类单例模式也称单例持有者模式,实例由内部类创建,由于JVM在加载外部类的过程中,是不会加载静态内部类的,只有内部类的属性/方法被调用时才会被加载,并初始化其静态属性。静态属性由static修饰,保证只被实例化一次,并且严格保证实例化顺序。静态内部类单例模式代码如下:

public class Singleton {
    private Singleton() {
 
    }
 
    private static class InstanceHolder {
        private final static Singleton instance = new Singleton();
    }
 
    public static Singleton getInstance() {
        return InstanceHolder.instance;
    }
}

7、枚举类实现(最佳)—线程安全

public class EnumSingleton {
 
    //私有化构造函数
    private EnumSingleton() {
    }
 
    public static EnumSingleton getInstance(){
        return Singleton.INSTANCE.getInstance();
    }
 
    private enum Singleton{
        INSTANCE;
        private final EnumSingleton singleton;
        //JVM保证这个方法绝对只能调用一次
        Singleton(){
            singleton=new EnumSingleton();
        }
        public EnumSingleton getInstance(){
            return singleton;
        }
 
    }
}

枚举类实现单例模式是effective java作者极力推荐的单例实现模式,因为枚举类型是线程安全的,并且只会装在一次,设计者充分
的利用了枚举的这个特性来实现单例模式,枚举的写法非常简单,而且枚举类型是所有单例实现中唯一一种不会被破坏的单例实现模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值