有的时候我们需要在系统中只对某个类只实例化一次,这就是我们今天要说的单例模式:实例化过程中只实例化一次。
单例模式一般的书写的规则:有一个实例化的过程(只有一次)产生实例化对象,并提供返回实例对象的方法。下面我就介绍几种常用的单例模式,同时我们会从线程的安全性、性能、懒加载几个方面分析每一种的单例模式。
-
饿汉式
public class HungerSingleton { private static HungerSingleton instance = new HungerSingleton(); private HungerSingleton() { } public static HungerSingleton getInstance() { return instance; } public static void main(String[] args) { for (int i = 0; i < 20; i++) { new Thread(() -> System.out.println(HungerSingleton.getInstance()) ).start(); } } }
运行上面的代码,查看的结果如下:
从运行的结果中可以看出是线程安全的。
线程安全性:在加载的时候已经被实例化,所以只有这一次,线程安全。
懒加载:没有延迟加载,好长时间不使用,影响性能。
性能:比较好
-
懒汉式
public class HoonSingleton { private static HoonSingleton instance = null; private HoonSingleton() { } public static HoonSingleton getInstance() { if (instance == null) { instance = new HoonSingleton(); } return instance; } public static void main(String[] args) { for (int i = 0; i < 20; i++) { new Thread(() -> System.out.println(HoonSingleton.getInstance()) ).start(); } } }
运行上面的代码,查看结果如下:
上面的运行结果,我们可以知道是线程不安全的。
线程安全:不能保证实例化的对象的唯一性
懒加载:是懒加载
性能:好
-
懒汉式+同步方法
public class HoonSyncSingleton { private static HoonSyncSingleton instance = null; private HoonSyncSingleton() { } public static synchronized HoonSyncSingleton getInstance() { if (instance == null) { instance = new HoonSyncSingleton(); } return instance; } public static void main(String[] args) { for (int i = 0; i < 20; i++) { new Thread(() -> System.out.println(HoonSyncSingleton.getInstance()) ).start(); } } }
线程安全:线程是安全,因为加了synchronized关键字,所以是线程安全的
懒加载:是懒加载
性能:synchronized 退化到了串行执行。
-
锁粒度细化+饿汉式+同步方法
public class HoonSyncSingletonDemo { private static HoonSyncSingletonDemo instance = null; private HoonSyncSingletonDemo() { } public static HoonSyncSingletonDemo getInstance() { if (instance == null) { synchronized (HoonSyncSingletonDemo.class) { instance = new HoonSyncSingletonDemo(); } } return instance; } public static void main(String[] args) { for (int i = 0; i < 20; i++) { new Thread(() -> System.out.println(HoonSyncSingletonDemo.getInstance()) ).start(); } } }
线程安全:线程是不安全的,因为如果两个线程同时进入if的判断,这个时候就会初始化两次。
懒加载:是懒加载
性能:性能比较好
-
DCL
public class DCL { private static DCL instance = null; private DCL() { } public static DCL getInstance() { if (instance == null) { synchronized (DCL.class) { if (null == instance) { instance = new DCL(); } } } return instance; } public static void main(String[] args) { for (int i = 0; i < 20; i++) { new Thread(() -> System.out.println(DCL.getInstance()) ).start(); } } }
线程安全:线程不是安全的。因为指令重排的原因,可能会返回空的对象。
懒加载:是懒加载
性能:性能比较好
-
volatile+DCL
public class DCL { private volatile static DCL instance = null; private DCL() { } public static DCL getInstance() { if (instance == null) { synchronized (DCL.class) { if (null == instance) { instance = new DCL(); } } } return instance; } public static void main(String[] args) { for (int i = 0; i < 20; i++) { new Thread(() -> System.out.println(DCL.getInstance()) ).start(); } } }
线程安全:线程安全
懒加载:是懒加载
性能:性能比较好
-
Holder :声明类的时候,成员变量中不声明实例变量,而放到内部静态类中
public class HolderDemo { private HolderDemo() { } private static class Holder{ private static HolderDemo instance = new HolderDemo(); } public static HolderDemo getInstance() { return Holder.instance; } }
线程安全:是线程安全的
懒加载:是懒加载的
性能:性能好
-
枚举
在看枚举前实现的前,我们先看看下面这个例子
public enum EnumDemo { A, B, C, D; public static void m1() { System.out.println("method"); } public static void main(String[] args) { A.m1(); B.m1(); C.m1(); D.m1(); System.out.println(A.getClass().getName()); System.out.println(B.getClass().getName()); System.out.println(C.getClass().getName()); System.out.println(D.getClass().getName()); } }
运行上面的程序,结果如下:
可以看到返回的就是当前的类。所以我们有了下面的单例模式
public enum EnumSingleton { INSTANCE; public static EnumSingleton getInstance() { return INSTANCE; } }
线程安全:是线程安全的
懒加载:不是懒加载的
性能:性能好
-
Holder+枚举
public class EnumHolderSingleton { private EnumHolderSingleton() { } public enum EnumHolder { INSTANCE; private EnumHolderSingleton instance; EnumHolder() { this.instance = new EnumHolderSingleton(); } private EnumHolderSingleton getInstance() { return instance; } } public static EnumHolderSingleton getInstance() { return EnumHolder.INSTANCE.instance; } }
线程安全:是线程安全的
懒加载:是懒加载的
性能:性能好