单例模式,是我们最常用也最熟悉的一种设计模式,其使用要注意线程安全。
定义
单例模式:顾名思义,就是在应用中有且只有一个实例。一般类似于计数器类的都必须是单例,多例会导致计数结果不准。
一般而言,其分为饿汉式和懒汉式。
懒汉式
懒汉式:顾名思义,就是不在系统加载时创建类的实例。而是在调用时才去一次性创建。
demo如下:
package com.singleton; /** * 懒汉式 * @author xiang.wei */ public class LazySingleton { /** * 定义一个私有变量,目的是外部不能直接访问该变量,必须通过公共的访问方法来访问 */ private static LazySingleton instance=null; /** * 私有化构造器,使之不能直接构造对象 */ private LazySingleton(){ } /** * 公共的提取对象的方法 * @return */ public synchronized static LazySingleton getInstance() { if (instance==null) { instance=new LazySingleton(); } return instance; } }
饿汉式
饿汉式:与懒汉式相反,饿汉式就是在系统加载时就去创建类的实例。
demo如下:
package com.singleton; /** * 饿汉式 * @author xiang.wei * @create 2018/4/10 10:34 */ public class HungrySingleton { private static final HungrySingleton SINGLETON = new HungrySingleton(); private HungrySingleton() { } public static HungrySingleton getInstance() { return SINGLETON; } }
总结:饿汉式与懒汉式相比要占用更多的内存,因为系统加载之后就会创建实例。但是效率要比懒汉式要高。
双重加锁
双重加锁是懒汉式的一种扩展。因为直接在getInstance()上加上synchronized会导致每次调用方法时都需要加锁。执行效率不高。所以,我们采用了双重加锁的方式。
package com.singleton; /** * 懒汉式 * 双重加锁 * @author xiang.wei */ public class LazySingleton_two { /** * 定义一个私有变量,目的是外部不能直接访问该变量,必须通过公共的访问方法来访问 */ private static volatile LazySingleton_two instance = null; /** * 私有化构造器,使之不能直接构造对象 */ private LazySingleton_two() { } /** * 公共的提取对象的方法 * * @return */ public static LazySingleton_two getInstance() { //如果单例存在则直接返回 if (instance == null) { //单例不存在,则进入同步代码块 synchronized (LazySingleton_two.class) { if (instance == null) { System.out.println("实例化的次数"); instance = new LazySingleton_two(); } } } return instance; } }
双重加锁并不是加两个synchronized关键字。
第一个判断是当对象存在时则直接返回实例,当对象不存在时则进入同步代码块中,同步代码块的作用跟之前是相同的,就是防止两个线程同时访问同步代码块的内容,造成生成多个实例的情况。同步代码块每次只允许一个线程进入,创建完实例后返回。第二个判断是当多个线程排队进入代码块时,第一个线程创建完实例返回后,第二个线程再进入时,不需要在创建实例。
采用双重加锁后,代码的执行效率有了较大的提升。
静态内部类的方式
public class MySingleton { private static class MySingletonHandle { private static final MySingleton instance = new MySingleton(); } private MySingleton() { } public MySingleton getSingleton() { return MySingletonHandle.instance; } }
注:Spring 容器中所有的Bean都是单例的
代码请见:
https://github.com/XWxiaowei/JavaCode/tree/master/design-patterns
参考
https://www.cnblogs.com/V1haoge/p/6510196.html