这次分享我们就来谈谈单例模式的使用,其实在本公众号设计模式的第一篇分享就是单例模式,为什么又要讨论单例模式了?主要是那篇文章谈的比较浅,只对单例模式的主要思想做了一个分享,这篇文章会从多个方面去分享单例模式的使用,下面进入正题。
使用Java做程序的小伙伴都知道单例,尤其是使用spring框架做项目的,大家都知道spring框架管理类默认都是单例模式的,并且是线程安全的。那么如果保证一个类只被初始化一次且线程安全了?带着这个问题我们开始这篇文章。
在刚接触设计模式的时候,大多数人首先接触到的第一个设计模式就是单例模式,当然大多数人都只停留在单例模式,在平时的开发中用的少之又少,这篇文章会帮助大家从多个方面理解单例模式,此文代码较多,如果对单例模式概念不是很清楚的小伙伴可以看另一篇文章《设计模式之单例模式》。
1. 懒汉模式
package com.study.concurrency.base_concurrency.example.singleton; /** * <p>Title: Singleton01</p > * <p>Description: 懒汉模式 单例实例在第一次使用时进行创建 </p > * <p>Company: http://www.yinjiedu.com</p > * <p>Project: concurrency</p > * * @author: qiwei * @Date: 2019/8/20 22:41 * @Version: 1.0 */ public class Singleton01 { private Singleton01() { } //单例对象 private static Singleton01 instance = null; /** * @description: 静态的工厂方法 * @auther: qiwei * @date: 2019/8/20 22:43 * @return: Singleton01 */ public static Singleton01 getInstance() { if (instance == null) { instance = new Singleton01(); } return instance; } }
上述代码在单线程下是没有问题的,但是在多线程情况下是线程不安全的,出现问题的代码主要是在下面这段代码:
2. 饿汉模式
为了解决上面懒汉模式线程不安全问题,我们可以使用饿汉模式创建类实例。饿汉模式是单例实例在类装载时进行创建,代码如下:
package com.study.concurrency.base_concurrency.example.singleton; /** * <p>Title: Singleton02</p > * <p>Description: 饿汉模式</p > * <p>Company: http://www.yinjiedu.com</p > * <p>Project: concurrency</p > * * @author: qiwei * @Date: 2019/8/20 22:53 * @Version: 1.0 */ public class Singleton02 { private Singleton02() { } //单例对象 private static Singleton02 instance = new Singleton02(); /** * @description: 静态的工厂方法 * @auther: qiwei * @date: 2019/8/20 22:55 * @return: Singleton02 */ public static Singleton02 getInstance() { return instance; } }
饿汉模式问题:
饿汉模式虽然是线程安全的,但是在实际开发中,会有一些大家需要注意的问题。
第一点:饿汉模式是在类装载的时候就创建的,所以如果类的构造方法里面很多复杂的处理,类装载就会比较慢,影响程序性能;
第二点:饿汉模式创建的示例,不管在项目其他地方有没有使用,类的实例已经创建,如果不使用,会造成资源的浪费。
基于以上两点,大家在使用饿汉模式的时候需要注意实际的使用场景。
3. 懒汉模式之线程安全
我们看到在使用懒汉模式创建实例时是线程不安全的,这里我们使用同步锁的方式,让懒汉模式也是线程安全的,代码如下:
package com.study.concurrency.base_concurrency.example.singleton; /** * <p>Title: Singleton01</p > * <p>Description: 懒汉模式 </p > * <p>Company: http://www.yinjiedu.com</p > * <p>Project: concurrency</p > * * @author: qiwei * @Date: 2019/8/20 22:41 * @Version: 1.0 */ public class Singleton03 { private Singleton03() { } //单例对象 private static Singleton03 instance = null; /** * @description: 静态的工厂方法 * @auther: qiwei * @date: 2019/8/20 22:43 * @return: Singleton01 */ public static synchronized Singleton03 getInstance() { if (instance == null) { instance = new Singleton03(); } return instance; } }
这里我们使用了synchronized关键字保证了线程安全,但是在实际开发中不要这样写,因为synchronized会带来比较严重的性能开销。
4. 懒汉模式之双重同步锁模式(线程不安全)
使用双重同步锁实现单例模式,代码如下:
package com.study.concurrency.base_concurrency.example.singleton; /** * <p>Title: Singleton01</p > * <p>Description: 懒汉模式 </p > * <p>Company: http://www.yinjiedu.com</p > * <p>Project: concurrency</p > * * @author: qiwei * @Date: 2019/8/20 2