单例设计模式

1.定义及特点

Singleton(单例)保证一个类仅有一个实例,并提供一个访问它的全局访问点。
特点:
(1)存在私有的构造函数,不能通过new来得到类的实例。
(2)私有的静态实例,一个class只能对应唯一的对象。
(3)只能通过:类.get方法获得这个唯一的对象实例。

2.饿汉单例和懒汉单例

1.饿汉单例模式:类加载时就已经进行实例化,无论之后用不用到。
优点:线程安全。类加载时完成初始化,获取对象的速度较快。
缺点:如果该类比较占内存,之后又没有用到,就会造成内存浪费。
适用场景:如果应用程序总是创建并使用单例实例或在创建和运行时开销不大。
饿汉单例模式:类加载时就已经进行实例化

public class HungerSingleton {

    private static HungerSingleton ourInstance = new HungerSingleton();

    public static HungerSingleton getInstance() {
        return ourInstance;
    }

    private HungerSingleton() {
    }

    public static void main(String[] args) {
    
            new Thread(()->{
                System.out.println(HungerSingleton.getInstance());
            }).start();
        }
}

2.懒汉单例模式:在需要的时候,再去创建实例。
优点:如果该类比较占内存,而且没怎么用到,则此种单例模式节省内存。
缺点:线程不安全。
适用场景:如果开销比较大,希望用到时才创建就要考虑延迟实例化,或者Singleton的初始化需要某些外部资源(比如网络或存储设备),就要用此种单例模式。
懒汉单例模式:在需要的时候再实例化

public class LazySingleton {

    private static volatile LazySingleton lazySingleton = null;

    private LazySingleton() {

    }

    public static LazySingleton getInstance() {
        
        if (null == lazySingleton) {

            lazySingleton = new LazySingleton();
        }

        
        return lazySingleton;
    }

    public static void main(String[] args) {

        new Thread(() -> {
            System.out.println(LazySingleton.getInstance());
        }).start();
    }
}
3.其他单例设计模式的实现

显然两种原生的单例设计模式不能应付纷繁复杂的应用场景,因此有以下单例设计模式的优化,使得能够应付不同的应用场景。
1.静态内部类: 根据jvm规范,当某对象第一次调用LazyInitHolderSingleton.getInstance()时,LazyInitHolderSingleton类被首次主动使用,jvm对其进行初始化(此时并不会调用LazyInitHolderSingleton()构造方法),然后LazyInitHolderSingleton调用getInstance()方法,该方法中,又首次主动使用了SingletonHolder类,所以要对SingletonHolder类进行初始化,初始化中,INSTANCE常量被赋值时才调用了 LazyInitHolderSingleton的构造方法LazyInitHolderSingleton(),完成了实例化并返回该实例。
当再有对象(也许是在别的线程中)再次调用LazyInitHolderSingleton.getInstance()时,因为已经初始化过了,不会再进行初始化步骤,所以直接返回INSTANCE常量即同一个LazyInitHolderSingleton实例。

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

2.同步方法的懒汉式:用来解决线程不安全的问题,加锁从而线程安全。但是每次同步,效率很低。

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

3.双重校验锁:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。实例变量需要加volatile 关键字保证易变可见性,JDK1.5起才可用。
volatile关键字及其使用场景
1.能且仅能修饰变量
2.保证该变量的可见性,volatile关键字仅仅保证可见性,并不保证原子性
3.禁止指令重排序(java中使用双重检查锁定机制,由于Java编译器和JIT的优化的原因系统无法保证我们期望的执行次序。在java5.0修改了内存模型,使用volatile声明的变量可以强制屏蔽编译器和JIT的优化工作)

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

4.枚举:从Java1.5开始支持enum特性;无偿提供序列化机制,绝对防止多次实例化,即使在面对复杂的序列化或者反射攻击的时候。

public enum Singleton {
    
    INSTANCE;
 
    /*
    **假如还定义有下面的方法,调用:Singleton.INSTANCE.doSomethingMethod();
    */
 
    public void doSomethingMethod() {
 
    }
4.jdk中单例设计模式的应用

饿汉单例设计模式:java.lang.Runtime#getRuntime()

public class Runtime {

    private static Runtime currentRuntime = new Runtime();
    
    private Runtime(){}
    
    public static Runtime getRuntime() {
    
        return currentRuntime;
    }
}

懒汉单例设计模式:java.awt.GraphicsEnvironment#getLocalGraphicsEnvironment()

public class GraphicsEnvironment {

    private static GraphicsEnvironment localEnv;
    
    protected GraphicsEnvironment(){}
    
    public static synchronized GraphicsEnvironment getLocalGraphicsEnvironment() {
        if (localEnv == null) {
            localEnv = createGE();
        }

        return localEnv;
    }
    
    private static GraphicsEnvironment createGE() {}
}

参考文章:
https://www.cnblogs.com/lc0605/p/10794607.html
https://www.cnblogs.com/Cubemen/p/10639096.html
https://blog.youkuaiyun.com/u013256816/article/details/50427061
https://www.cnblogs.com/binaway/p/8889184.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值