博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java23种设计模式之二: 单例设计模式(6种写法)
阅读量:7163 次
发布时间:2019-06-29

本文共 3435 字,大约阅读时间需要 11 分钟。

 

目的:在某些业务场景中,我们需要某个类的实例对象的只能有一个,因此我们需要创建一些单例对象。

本文共有6种写法,仅供参考

 

1.饿汉式

 

  优点: 在多线程情况下,该方法创建的单例是线程安全的(立即加载

 

  缺点: 由于instance 是由静态修饰的,所以在加载类之前就会将instance 加载到方法区中,如果长时间不用,这样会长时间占用内存。

public class SingletonObject1 {        private static final SingletonObject1 instance = new SingletonObject1();        private SingletonObject1() {        //empty    }    public static SingletonObject1 getInstance() {        return instance;    }}

2.懒汉式(Unsafe)

  优点:只有在使用时才会被创建,不会在初始化时消耗大量内存

  缺点:线程是不安全的。当被多个线程调用时,线程是不安全,需要在获取实例方法添加synchronized

public class SingletonObject2 {    private static SingletonObject2 instance;        private SingletonObject2() {        //empty    }    public static SingletonObject2 getInstance() {        if(instance ==null){            instance = new SingletonObject2();        }        return SingletonObject2.instance;    //此种写法更直观,可以看出是某个类的实例变量      }}

3.懒汉式(security)

  优点:只有在使用时才会被创建,不会在初始化时消耗内存,同时又确保了线程是安全的

  缺点:虽然保证线程是安全,由于加了同步锁会在并发访问时影响性能

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

4.懒汉式(double check)

     在示例3中,在getInstance()获取实例的方法是同步的,其目的是为了防止多个线程在获取实例时并发的创建多个对象,但是这样影响了访问的效率,既然是为了防止多线程并发访问,那我们可以把同步方法改成同步代码块,在创建instance 实例处加上同步代码块,当线程1访问instance == null;进来拿到同步锁,将实例创建完成才释放锁,当线程2访问时,instance 已经不等于null 直接返回了实例。

  优点:在使用时都会被创建,访问效率高、线程安全

  缺点:可能会实现空指针情况

public class SingletonObject4 {    private static  SingletonObject4 instance;        private SingletonObject4() {        //empty    }    /**     * synchronized处:当线程1执行完创建实例释放锁后,线程2执行到标红处代码时,得到实例不等于null,于是     * 返回拿到了返还的实例,可能这样解释你觉得怎么会出现这种情况,但这种情况确实会出现,是因为java     * 的happens-before规则导致的,在代码编译后,编译器和处理器会进行优化处理,但在在堆内存创建     * 对象后直接返回了,可能还没有将对象的一些属性初始化完成,而线程2得到的实例可能会出现空指针的情况。     *                                     */    public  static SingletonObject4 getInstance() {        if(instance == null) {            synchronized (SingletonObject4.class) {                if(instance ==null){                    instance = new SingletonObject4();                }             }        }        return SingletonObject4.instance;        }}

5.懒汉式(volatile security)

  优点:在使用时都会被创建,访问效率高、线程安全

  缺点:如果对关键字性能不了解,这种写法可能不太会被接受

    volatile:虽然不能保证原子性,但保证内存的可见性,即多个线程看到的数据是同一份,它在加载读的时候,会保证所有写的操作完成之后,才会去读,即保证了在创建对象的时候会保证对象完全初始化创建完成。

 

public class SingletonObject5 {    private static  volatile  SingletonObject5 instance;        private SingletonObject5() {        //empty    }    public  static SingletonObject5 getInstance() {        if(instance == null) {            synchronized (SingletonObject4.class) {                if(instance ==null){                    instance = new SingletonObject5();                }             }        }         return SingletonObject5.instance;        }}

 

6.静态内部类(inner_static)

  优点:

    1.static 修饰的类,只有使用到时才会进行加载,而且只加载1

    2.这种方式是通才内部类调用外部类构造函数,同时提供1种对外访问的方法来实现的

  缺点:需要对jvm加载class的时机掌握的比较清楚

 

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

 

转载于:https://www.cnblogs.com/MrRightZhao/p/10463313.html

你可能感兴趣的文章