一、简介
单例模式在单线程环境下的两种经典实现:饿汉式 和 懒汉式。但是饿汉式是线程安全的,而懒汉式是非线程安全的。在多线程环境下,我们特别介绍了五种方式来在多线程环境下创建线程安全的单例,即分别使用 synchronized方法、synchronized块、静态内部类、双重检查模式 和 ThreadLocal 来实现懒汉式单例,并总结出实现效率高且线程安全的懒汉式单例所需要注意的事项。
二、代码实现
2.1单线程环境下
1.饿汉式单例(立即加载)
//饿汉式单例(立即加载)
public class SingleModule {
//指向自己实例的私有静态引用,主动创建
private static SingleModule singleModule = new SingleModule();
//私有的构造方法
private SingleModule(){}
//以自己实例为返回值的静态公有方法,静态工厂方法
public static SingleModule getInstance(){
return singleModule;
}
}
2.懒汉式单例(延迟加载)
//懒汉式单例(延迟加载)
public class SingleModule{
//指向自己实例的私有静态引用
private static SingleModule singleModule;
//私有的构造方法
private SingleModule(){}
//以自己实例为返回值的静态公有方法,静态工厂方法
public static SingleModule getInstance(){
//被动创建,在真正需要使用时才去创建
if(singleModule == null){
singleModule = new SingleModule();
}
return singleModule;
}
}
2.2多线程环境下
1.线程安全的懒汉式单例(同步延迟加载 — synchronized方法)
//1.线程安全的懒汉式单例(同步延迟加载 — synchronized方法)
public class SingleModule{
private static SingleModule singleModule;
private SingleModule() { }
//使用 synchronized 修饰,临界资源的同步互斥访问
public static synchronized SingleModule getInstance(){
if(singleModule == null){
singleModule = new SingleModule();
}
return singleModule;
}
}
2.线程安全的懒汉式单例(同步延迟加载 - synchronized块)
//2.线程安全的懒汉式单例(同步延迟加载 - synchronized块)
public class SingleModule{
private static SingleModule singleModule;
private SingleModule(){}
public static SingleModule getInstance(){
synchronized (SingleModule.class){
if(singleModule == null){
singleModule = new SingleModule();
}
}
return singleModule;
}
}
3.线程安全的懒汉式单例(同步延迟加载 - 使用内部类实现延迟加载)
//3.线程安全的懒汉式单例(同步延迟加载 - 使用内部类实现延迟加载)
public class SingleModule{
private static class Holder{
private static SingleModule singleModule = new SingleModule();
}
private SingleModule(){}
public static SingleModule getInstance(){
return Holder.singleModule;
}
}
4.线程安全的懒汉式单例(双重检查)
//线程安全的懒汉式单例(双重检查)
public class SingleModule{
//使用volatile关键字防止重排序,因为new Instance()是一个非原子操作,可能创建一个不完整的实例
private static volatile SingleModule singleModule;
private SingleModule(){}
public static SingleModule getInstance(){
//Double-Check idiom
if(singleModule == null){
synchronized (SingleModule.class){ //第一步
//只需要在第一次创建实例时才同步
if(singleModule == null){ //第二步
singleModule = new SingleModule(); //第三步
}
}
}
return singleModule;
}
}
5.线程安全的懒汉式单例(ThreadLocal)
//线程安全的懒汉式单例(ThreadLocal)
public class SingleModule{
private static ThreadLocal<SingleModule> threadLocal = new ThreadLocal<SingleModule>();
private static SingleModule singleModule = null;
private SingleModule(){}
public static SingleModule getInstance(){
if(threadLocal.get() == null){//第一次检查:该线程是否是第一次访问
createSingleModule();
}
return singleModule;
}
private static void createSingleModule() {
synchronized (SingleModule.class){
if(singleModule == null){ //第二次检查:该单例是否被创建
singleModule = new SingleModule(); //只执行一次
}
}
threadLocal.set(singleModule);
}
}