标签:turn new 多线程 顺序 首次加载 stat cal 情况 需要
单例模式(Single Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。即需要隐藏其所有的构造方法,只能通过全局访问点来创建。
常见的单例有:ServletContext、ServletConfig、ApplicationContext、DBPool。
单例分为饿汉式单例,懒汉式单例,注册式单例,ThreadLocal单例。
饿汉式单例
饿汉式单例是指在单例类首次加载时就创建实例,缺点是:浪费内存空间。即不管用不用,也不管什么时候用,先创建,放着,占着内存空间。饿着,先吃饱。
public class HungrySingleton { //第一步,不管用不用,也不管什么时候用,先创建出来,占着内存空间 private static final HungrySingleton instance = new HungrySingleton(); //第二步,私有化构造方法,也即隐藏构造方法 private HungrySingleton(){}; //第三步,提供一个全局访问点,并返回创建的实例 public static HungrySingleton getInstance(){ return instance; } }
第二种,高端一点的饿汉式单例
public class HungryStaticSingleton { //第一步,不管用不用,也不管什么时候用,先创建出来,占着内存空间 private static final HungryStaticSingleton instance; static{ instance = new HungryStaticSingleton(); } //第二步,私有化构造方法,也即隐藏构造方法 private HungryStaticSingleton(){}; //第三步,提供一个全局访问点,并返回创建的实例 public static HungryStaticSingleton getInstance(){ return instance; } }
这两种方式,都叫做饿汉式单例写法。
缺点:不管用不用,都初始化,如果大批量的采用这种写法,造成内存的浪费。
第二种为什么写在static块中呢?这是涉及到java的类加载机制,即:先静态后动态,先属性后方法,先上后下。所以写在static中,创建较快。
懒汉式单例
懒汉式单例是指先定义好类,被外部内调用的时候再创建实例。不用就一直不创建。
public class lazySimpleSingleton { // 第一步,先定义好 private static lazySimpleSingleton instance; // 第二步,私有化构造方法,也即隐藏构造方法 private lazySimpleSingleton() {}; // 第三步,提供一个全局访问点,如果没有就创建 public static lazySimpleSingleton getInstance() { if (instance == null) { instance = new lazySimpleSingleton(); } return instance; } }
优点:解决内存空间浪费的问题。但是风险是:有可能创建多个不同的实例(在多线程中可能创建多个不同的实例,也即违背了单例模式)。即饿汉式变成懒汉式有线程安全问题。产生的原因是:多个线程同时进入,同时判断,导致同时创建,也即创建了两个不同的对象。
解决方法,加锁
public class lazySimpleSingleton { // 第一步,先定义好 private static lazySimpleSingleton instance; // 第二步,私有化构造方法,也即隐藏构造方法 private lazySimpleSingleton() {}; // 第三步,提供一个全局访问点,如果没有就创建 public static synchronized lazySimpleSingleton getInstance() { if (instance == null) { instance = new lazySimpleSingleton(); } return instance; } }
加锁过后,执行new就有了顺序。
但是锁类,会发生阻塞,如果锁方法呢?
public class LazyDoubleCheckSingleton { // 第一步,先定义好 private static LazyDoubleCheckSingleton instance; // 第二步,私有化构造方法,也即隐藏构造方法 private LazyDoubleCheckSingleton() {}; // 第三步,提供一个全局访问点,如果没有就创建 public static LazyDoubleCheckSingleton getInstance() { //不是任何时候进来都要加锁,只有创建对象才加锁 if(instance == null){ //锁方法,不会发生阻塞 synchronized (LazyDoubleCheckSingleton.class) { if (instance == null) { instance = new LazyDoubleCheckSingleton(); } } } return instance; } }
这即是双重检查锁。
标签:turn new 多线程 顺序 首次加载 stat cal 情况 需要
原文地址:https://www.cnblogs.com/xiangpeng/p/11042694.html