Java单例设计模式

什么是单例设计模式

某个类在整个系统中,只存在一个实例对象可获取和使用

要点

  • 一个类只能有一个实例对象

    构造器私有化

  • 必须自行创建这个实例

    含有一个该类的静态变量来存储这个实例

  • 向整个系统提供这个实例

    对外提供获取该实例的方式

单例设计模式分类

单例设计模式分为两大类:懒汉式、饿汉式

饿汉式:顾名思义,我现在非常饿,我看到一个面包马上就要把他吃下去。所以在整个系统加载时,不管你用不用得到这个对象,都直接创建。

懒汉式:也挺好理解,我非常懒,有严重拖延症,不到万不得已的时候不干。也就是说,只有当我需要使用这个对象时,才创建它。

饿汉式实现

因为在系统加载时就创建了这个对象,所以饿汉式是线程安全的。有三种方法可以实现饿汉式。

直接实例化饿汉式(简洁直观)

public class Singleton1 {
    //2.用一个静态对象存储该实例
    public static final Singleton1 INSTANCE = new Singleton1();
    //1.构造器私有化
    private Singleton1(){

    }
}

枚举方式(最便捷)

public enum Singleton2 {
    INSTANCE
}

静态代码块饿汉式

其实效果是一样的,不过静态代码块更适合在初始化时设置复杂的参数

如果创建有参构造方法,而我们有希望从外部配置文件读取到参数,那就可以使用静态代码块的方式来创建

public class Singleton3 {
    private static final Singleton3 INSTANCE;
    
    static {
        INSTANCE = new Singleton3();
    }
    
    private Singleton3(){
        
    }
}

懒汉式实现

线程不安全的(适用于单线程)

public class Singleton4 {
    //2.用一个静态对象存储该实例
    private static Singleton4 INSTANCE;
    //1.构造器私有化
    private Singleton4(){

    }
    //3.通过方法来暴露实例
    public static Singleton4 getInstance(){
        if(INSTANCE == null){
            INSTANCE = new Singleton4();
        }
        return INSTANCE;
    }
}

可以通过以下方法来测试线程不安全

public class Singletontest4 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Singleton4> c = new Callable<Singleton4>() {
            @Override
            public Singleton4 call() throws Exception {
                Singleton4 s = Singleton4.getInstance();
                return s;
            }
        };

        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<Singleton4> submit1 = es.submit(c);
        Future<Singleton4> submit2 = es.submit(c);
        Singleton4 s1 = submit1.get();
        Singleton4 s2 = submit2.get();
        System.out.println(s1);
        System.out.println(s2);
    }
}

线程安全的(适用于多线程)

线程安不安全,无非就是加一把锁

public class Singleton5 {
    //2.用一个静态对象存储该实例
    private static Singleton5 INSTANCE;
    //1.构造器私有化
    private Singleton5(){

    }
    //3.通过方法来暴露实例
    public static Singleton5 getInstance(){
        if(INSTANCE == null){
            synchronized (Singleton5.class) {
                INSTANCE = new Singleton5();
            }
        }
        return INSTANCE;
    }
}

静态内部类形式(适用于多线程)

将初始化方法放入一个静态内部类中调用,绝对是线程安全的

public class Singleton6 {
    private Singleton6(){

    }

    private static class Inner{
        private static final Singleton6 INSTANCE = new Singleton6();
    }

    public static Singleton6 getInstance(){
        return Inner.INSTANCE;
    }
}
上一篇:30个类手写Spring核心原理之依赖注入功能(3)


下一篇:Java单例模式实现,一次性学完整,面试加分项