个人整合学习自
- 《Java设计模式》 刘伟 编著
单例模式
Singleton Pattern:确保一个类职业一个实例,并提供一个全局访问点来访问这个唯一实例。也是一直创建型模式。
单例模式的三个要点:
- 某个类只能有一个实例;
- 它必须自行创建这个实例;
- 它必须自行向整个系统提供这个实例。
实现
1. 饿汉式单例
package xyz.cglzwz.designpattern.sp;
/**
* 饿汉式单例
* @author chgl16
* @date 2019-04-02
*/
public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return instance;
}
}
当类加载时,静态变量instance会被初始化,此时类的私有构造函数会被调用,单例类的唯一实例将被创建。(叫饿汉是eager的意思,渴望第一时间加载)
- 优点:无需考虑多线程同时访问的问题,可以确保实例的唯一性,而且调用速度和反应时间比以下的懒汉模式要优。
- 缺点:类加载时就创建,加载时间可能比较长。
2. 懒汉式单例
package xyz.cglzwz.designpattern.sp;
/**
* 懒汉式单例模式
*
* @author chgl16
* @date 2019-04-02
*/
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() {}
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
懒汉式都是在第一次调用getInstance()方法时初始化实例,在类加载时并不自行创建,这种技术也称为延迟加载(Lazy Load)技术。
上面代码虽然增加了synchronized修饰符进行线程隐式锁定,解决了线程安全问题。但是多线程高并发访问环境还是会大大降低系统性能。因此可以代码优化下,因为这里可见只需对 instance = new LazySingleton(); 锁定即可。如下改进
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
synchronized(LazySingleton.class) {
instance = new LazySingleton();
}
}
return instance;
}
}
问题貌似解决,但是并非如此。如果多个线程都同时到了 "if (instance == null) "为 true的情况,都通过了判断,由于事先了synchronized加锁机制,只是某一个线程创建了对象。但是后面的线程不知道,会继续创建的(因为已经通过判断了)。
继续改进,使用双重检查锁定
package xyz.cglzwz.designpattern.sp;
/**
* 懒汉模式双重检查锁定
* @author chgl16
* @date 2019-04-03
*/
public class LazySingleton2 {
// 使用volatile修饰,确保每个线程能够正确处理
private volatile static LazySingleton2 instance = null;
private LazySingleton2() {}
public static LazySingleton2 getInstance() {
// 第一重判断
if (instance == null) {
// 锁定代码块
synchronized (LazySingleton2.class) {
// 第二重判断
if (instance == null) {
// 创建单例实例
instance = new LazySingleton2();
}
}
}
return instance;
}
}