单例模式的七种写法

转行程序员

共 2596字,需浏览 6分钟

 ·

2021-08-31 08:39

本文思维导图。

c646b14930c91d1de0f1f5994fe55caa.webp




01懒汉
public class LazySingleTon {    private static LazySingleTon lazySingleTon = null;
    private LazySingleTon() {}
public static LazySingleTon getLazySingleTon() { if (lazySingleTon == null) lazySingleTon = new LazySingleTon(); return lazySingleTon; }}
先将引用lazySingleTon置为null,等到需要时才创建对象并将引用指向它。

此写法线程不安全,因为多个线程同时执行 if (lazySingleTon == null) 时,条件成立,多个线程会继续执行下面创建对象的代码,此时就不是单例,而是“多例”了。



02懒汉变种


public class LazySingleTon {    private static LazySingleTon lazySingleTon = null;
private LazySingleTon() {}
public static synchronized LazySingleTon getLazySingleTon() { if (lazySingleTon == null) lazySingleTon = new LazySingleTon(); return lazySingleTon; }}
不知道该写法的名字,暂且就叫它懒汉变种吧。
它使用synchronized关键字对getLazySingleTon()加锁,这样每个时刻只能有一个线程执行该方法,解决了懒汉模式中多线程同时执行的问题,此写法线程安全



03饿汉


public class SingleTonTest {    private static SingleTonTest singleTonTest = new SingleTonTest();
    private SingleTonTest() {}
public static SingleTonTest getInstance() { return singleTonTest; }}
饿汉写法,类SingleTonTest被加载时就会初始化singleTonTest对象,保证了系统中只有一个该类的实例对象,线程安全



04饿汉变种


public class SingleTonTest {    private static SingleTonTest singleTonTest = null;
static { singleTonTest = new SingleTonTest(); }
private SingleTonTest() { }
public static SingleTonTest getInstance() { return singleTonTest; }}
其实和饿汉写法差不多,只不过将创建对象放进了静态代码块。线程安全



05双重检测机制


public class DoubleLockSingleTon {    private static volatile DoubleLockSingleTon dlst = null;    private DoubleLockSingleTon(){}
public DoubleLockSingleTon getDlst(){ if (dlst==null){ synchronized (DoubleLockSingleTon.class){ if(dlst==null){ dlst = new DoubleLockSingleTon(); } } } return dlst; }}
双重检测机制在懒汉写法的基础上使用了双重判空+synchronized+volatile线程安全
注意两点:
  1. synchronized锁住的是DoubleLockSingleTon类对象,而不是实例对象。
  2. volatile关键字一定要有,它在此处的主要作用是禁止指令重排序,否则就不是绝对的线程安全了。



06静态内部类


public class StaticInnerClass {    private StaticInnerClass(){}
static class InnerClassSingleTon{ private static final StaticInnerClass sic = new StaticInnerClass(); }
public static StaticInnerClass getSic(){ return InnerClassSingleTon.sic; }
}
参照饿汉模式,此写法相当于将创建对象的代码放进了静态内部类中,这样一来,就实现了懒加载
也就是说当类StaticInnerClass被加载时,单例对象不一定会被创建,只有调用了getSic()时,类InnerClassSingleTon才会被加载,然后创建单例对象。线程安全。然而,该写法虽线程安全,但是可通过反射来创建多个实例对象。解决方法是使用枚举



07枚举


public enum SingleTon {    INSTANCE;}
不得不说,使用枚举实现单例模式代码非常简洁。它有两个优点:
  1. 线程安全。
  2. 能防止使用反射创建多个对象。

但是此写法不常见,想必大家最熟悉的写法就是懒汉和饿汉了...当然,我也是。

10256e477d3fe8dfff8139fbdd881f49.webp


b6d69d77345a41ab6ab0154fb9fa0535.webp

扫码关注,一起学习

BeCoder


浏览 17
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报