java设计模式-单例模式
Posted 醉东风
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java设计模式-单例模式相关的知识,希望对你有一定的参考价值。
单例模式
定义
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建型模式。
实现步骤
(1) 定义静态私有成员变量
(2) 创建唯一实例(多种实现方式)
(3) 定义私有构造函数,确保外部不能使用new关键字创建对象
(4) 提供外部获取单例对象的静态方法
实现方式
饿汉式单例类
饿汉式单例类是最简单的单例类,定义的静态私有成员变量在类加载的时候就会创建单例对象。饿汉式单例是线程安全的,不会出现创建多个单例对象的情况。
代码实现
/** * 饿汉式单例类 * @create 2018-04-12 17:05 **/ public class EagerSingleton { //定义静态私有成员变量,创建单例对象 private static EagerSingleton instance = new EagerSingleton(); //定义私有构造函数,确保外部不能使用new关键字创建EagerSingleton实例对象 private EagerSingleton() { } //提供外部获取单例对象的静态方法 public static EagerSingleton getInstance() { return instance; } }
优缺点
优点:线程安全,在多线程下不会出现创建多个实例对象的情况。
缺点:未实现懒加载,类加载时即初始化单例对象,加载时间可能较长。
懒汉式单例类
懒汉式单例也是一种实现单例的经典方式,单例对象不是在类加载时创建,而是在第一次调用getInstance方法时创建,实现了懒加载,但是在多线程下会出现创建多个单例对象的情况。
非线程安全代码实现
/** * 非线程安全懒汉式单例类 * @create 2018-04-12 22:14 **/ public class LazySingleton { //定义静态私有成员变量 private static LazySingleton instance = null; //定义私有构造函数,确保外部不能使用new关键字创建EagerSingleton实例对象 private LazySingleton() { } //提供外部获取单例对象的静态方法 public static LazySingleton getInstance() { if (null == instance) { //创建单例对象 instance = new LazySingleton(); } return instance; } }
优缺点
优点:实现懒加载
缺点:非线程安全,在多线程下不能正常工作
线程安全代码实现
/** * 线程安全懒汉式单例类 * @create 2018-04-12 22:14 **/ public class LazySingleton { //定义静态私有成员变量 private static LazySingleton instance = null; //定义私有构造函数,确保外部不能使用new关键字创建EagerSingleton实例对象 private LazySingleton() { } //创建实例对象时,加上线程锁,实现线程安全 public static synchronized LazySingleton getInstance() { if (null == instance) { //创建单例对象 instance = new LazySingleton(); } return instance; } }
优缺点
优点:实现懒加载、线程安全。
缺点:由于给getInstance方法加了线程锁,每次调用该方法时,都会被锁住,在多线程环境下,运行效率很低。
可以给上面这种方式进行优化,线程锁加载创建单例对象的地方,而不直接加在getInstance方法上。
优化后的代码:
package com.lnjecit.singleton; /** * 线程安全懒汉式单例类 * * @create 2018-04-12 22:14 **/ public class LazySingleton { //定义静态私有成员变量 private static LazySingleton instance = null; //定义私有构造函数,确保外部不能使用new关键字创建EagerSingleton实例对象 private LazySingleton() { } //创建实例对象时,加上线程锁,实现线程安全 public static LazySingleton getInstance() { if (null == instance) { synchronized (LazySingleton.class) { //创建单例对象 instance = new LazySingleton(); } } return instance; } }
这种方式可以在一点程度上提高运行效率,但是还是在多线程情况下,还是有可能出现创建多个单例,当instance为null时,多个线程同时访问getInstance方法,由于instance为null,所以都会创建instance对象,
造成出现多个实例。
双重锁定
代码实现
/** * 双重校验锁定单例类 * @create 2018-04-12 22:14 **/ public class LazySingleton { /** *定义静态私有成员变量, *使用volatile关键字修饰,确保线程可见性,当一个线程修改了instance对象,其它线程也能看到修改后的值 */ private volatile static LazySingleton instance = null; //定义私有构造函数,确保外部不能使用new关键字创建EagerSingleton实例对象 private LazySingleton() { } //创建实例对象时,加上线程锁,实现线程安全 public static LazySingleton getInstance() { if (null == instance) { synchronized (LazySingleton.class) { if (null == instance) { //创建单例对象 instance = new LazySingleton(); } } } return instance; } }
优缺点
优点:实现懒加载、线程安全。
缺点:volitile关键字会屏蔽JVM对代码的优化,存在导致运行效率低的可能。
内部静态类
饿汉式单例类不能实现懒加载,懒汉式需要加锁、判断等方式确保线程安全,实现过程繁琐。而在单例内中增加一个内部静态类可减少加锁和判断的过程,就可实现懒加载和线程安全,并且不影响运行效率。
实现代码
/** * 静态内部类 * @create 2018-04-12 17:05 **/ public class Singleton { //定义私有构造函数,确保外部不能使用new关键字创建EagerSingleton实例对象 private Singleton() { } private static class SingletonHolder { //创建单例对象 private static final Singleton INSTANCE = new Singleton(); } //提供外部获取单例对象的静态方法 public static Singleton getInstance() { return SingletonHolder.INSTANCE; } }
优缺点
优点:懒加载、线程安全。
缺点:
应用场景
请参考:
https://blog.csdn.net/lovelion/article/details/7420889
https://blog.csdn.net/tanyujing/article/details/14160941
参考资料
1、https://blog.csdn.net/lovelion/article/details/7420886
以上是关于java设计模式-单例模式的主要内容,如果未能解决你的问题,请参考以下文章