欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

单例模式的几种创建方式

程序员文章站 2022-07-14 09:25:09
...

1、饿汉式

public class Demo1 {
    private static Demo1 instance = new Demo1();
    private Demo1(){
    }
    public static Demo1 newInstance(){
        return instance;
    }
    public static void main(String[] args) {
        Demo1 demo1 = Demo1.newInstance();
        Demo1 demo2 = Demo1.newInstance();
        System.out.println(demo1 == demo2);
    }
}

单例模式的构造器都是私有的
这种方式是线程安全的,在类加载的过程中创建;缺点是如果这个类没有被使用过的话,导致资源的浪费

2、懒汉式

public class Demo2 {
    private static Demo2 instance = null;
    private Demo2(){}
    public static Demo2 newIntance(){
        if(instance == null){
            instance = new Demo2();
        }
        return instance;
    }
    public static void main(String[] args) {
        Demo2 demo2 = Demo2.newIntance();
        Demo2 demo21 = Demo2.newIntance();
        System.out.println(demo2 == demo21);
    }
}

优点:该模式在需要的时候才创建(懒加载);
缺点:非线程安全的

if(instance == null){
    instance = new Demo2();
}

如果线程同时进入这块区域,就会造成Demo2多次创建

3、改进懒汉模式

在newInstance方法上加锁synchronized
这种方式解决了线程安全的问题和懒加载的问题,但是如果这个对象已经创建了,而我以后每次调用都会加锁,影响效率

4、双重锁检模式

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

缺点:这个也不是线程安全的,因为会产生指令重排

改进加volatile关键字

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

通过双重锁检+volatile ,这样就真正做到了线程安全和懒加载了

5、静态内部类

public class Demo4 {
    private Demo4(){}
    
    private static class SDemo4{
        private static Demo4 instance = new Demo4();
    }

    public static Demo4 getInstance(){
        return SDemo4.instance;
    }
}

在一个类被加载的时候并不会加载其静态内部类,只有当其中的某个静态成员(静态域、构造器、静态方法等)被调用时,才会加载这个内部类;而且类加载的过程是线程安全的。

当然如果通过反射的方式创建该对象,这就不是单例的了

public static void main(String[] args) throws Exception {
        Demo4 d1 = Demo4.getInstance();
        Class<Demo4> clzz = Demo4.class;
        Constructor<Demo4> declaredConstructor = clzz.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);
        Demo4 d2 = declaredConstructor.newInstance();
        System.out.println(d1 == d2);//false
    }

6、通过枚举创建单例

public enum  Demo5 {
    INSTANCE;
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public void doSomeThing(){
        System.out.println("hello world");
    }

    @Override
    public String toString() {
        return "[" + name + "]";
    }
}
public static void main(String[] args) throws Exception {
        Demo5.INSTANCE.doSomeThing();
    }

推荐使用枚举

相关标签: java