Java设计模式二:深入理解单例模式

前言

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。

这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。

这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

定义

单例模式: 一个类有且只有一个实例,且提供一个全局访问方法来访问这个实例。

注:1、被static修饰的变量成为静态变量,当类加载器将类加载到JVM中的时候就会创建静态变量,这跟对象是否创建无关。

       2、静态代码块:静态代码块的代码只会在类第一次初始化的时候执行一次。

       3、静态变量创建后,会一直放在内存中,只有进程被杀掉时,才会被清空。这也是单例模式的核心。

单利模式

1、饿汉模式

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

缺点是在类加载的时候就实例化了对象,有点浪费空间,优点是线程安全,因为static变量会在类装载的时候初始化,并且多个实例的static变量会共享一块内存区域。

2、懒汉模式

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

但是由于线程不安全,于是加上了synchronized关键字修饰方法

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

加上锁以后又影响性能,于是又有了双锁检测(DCL)版本的单例模式(双重检查+锁)

public class Singleton {
        private static volitile Singleton singleton = null;

        private Singleton() {
        }

        public Singleton getInstance() {
            if (singleton == null) {
                synchronized (this) {
                    if (singleton == null) {
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }
}

1.为什么要进行第一次判空

如果说我们没有第一次验校,每一个线程都要走synchronized 中的代码,而每一次线程都要去拿到同步锁才能执行。在多线程的情况下每一个线程要拿到single 对象都要排队等待同步锁释放。因此第一次验校作用就是为了提高程序的效率。

2.为什么要进行第二次判空

如果有两个线程A和B都通过了第一次判空,进入到获取锁阶段A拿到锁进行对象创建后释放锁,此时B就不需要在创建对象,所以再次判断不为空,直接返回。

3.变量为什么要加volatile关键字

volatile防止指令重排序,single = new Single() 在我们看来就是一句话操作而已,但在虚拟机看来它一共分为了几个指令操作:

  • 为对象分配内存空间
  • 初始化对象
  • 将引用指向对象的内存空间地址

假如线程A执行 single = new Single()虚拟机是按132排序执行,当执行到3的时候single 引用已经不为空。此时若线程B执行到第一次验校处(第一次验校不在同步代码中,因此所有线程随时都可以访问),它判断 single ==null 得到false,直接返回single对象。但是此时single对象还没初始化完成,因此很有可能就会发生bug。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章