单例模式
Posted xiangpeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式相关的知识,希望对你有一定的参考价值。
单例模式(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;
这即是双重检查锁。
以上是关于单例模式的主要内容,如果未能解决你的问题,请参考以下文章