创建型
设计模式之单例模式
简介
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意⚠️:
- 单例类只能有一个实例
- 单例类必须通过自己创建自身的实例
- 单例类必须为所有类提供自身的唯一实例
单例模式的实现有很多种:
- 懒汉式
- 饿汉式 常用
- DCL双检锁模式(double-check-lock) 常用
- 静态Holder模式 常用
- 枚举 可以使用
要实现单例模式,需要完成以下几点:
1、私有化构造器,不能通过new来创建该类的实例
2、将自身对象作为自身的私有化静态属性
3、通过getInstance()方法获取实例
1 懒汉式
懒汉式本身不能保证线程安全,但是能保证lazy装载,假如懒汉式样需要保证线程安全,需要用到synchronized关键字修饰获取实例的方法。
1.1 线程不安全懒汉式
package com.shufang.create_type.allsingletons;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 1、延迟加载
* 2、线程不安全
* 3、懒汉式
*/
public class NotSafeLazySingleton {
private static NotSafeLazySingleton notSafeLazySingleton;
private NotSafeLazySingleton() {
System.out.println("initailizing");
}
public static NotSafeLazySingleton getInstance() {
if (notSafeLazySingleton == null) {
notSafeLazySingleton = new NotSafeLazySingleton();
}
return notSafeLazySingleton;
}
public static void main(String[] args) {
/**
* initailizing
* initailizing
* initailizing
* initailizing
* com.shufang.create_type.allsingletons.NotSafeLazySingleton@6419af39
* com.shufang.create_type.allsingletons.NotSafeLazySingleton@b20b63
* com.shufang.create_type.allsingletons.NotSafeLazySingleton@6419af39
* com.shufang.create_type.allsingletons.NotSafeLazySingleton@6419af39
* TODO 构造器被调用了4次,说明在多线程的情况下,构造器被调用了4次
*/
ExecutorService pool = Executors.newFixedThreadPool(10);
for (int i = 1; i < 50; i++) {
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println(NotSafeLazySingleton.getInstance());
}
});
pool.shutdownNow();
}
}
}
1.2 线程安全的懒汉式
package com.shufang.create_type.allsingletons;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 线程安全的懒汉式单例模式
* 延迟加载
* 线程安全
* 懒汉式
* NOTE:懒汉式没有将方法加synchronized修饰的会有线程安全问题
*/
public final class SafeLazySingleton {
//私有化静态属性
private static SafeLazySingleton safeLazySingleton;
//私有化构造器
private SafeLazySingleton() {
System.out.println("inited");
}
//静态方法获取实例对象
public static synchronized SafeLazySingleton getInstance() {
if (safeLazySingleton == null) {
safeLazySingleton = new SafeLazySingleton();
}
return safeLazySingleton;
}
// 测试利用多线程创建该实例
public static void main(String[] args) {
//创建固定数量线程池
ExecutorService pool = Executors.newFixedThreadPool(10);
for (int i = 0; i < 50; i++) {
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println(SafeLazySingleton.getInstance());
}
});
}
pool.shutdownNow();
}
}
2 饿汉式
饿汉式能保证线程安全,但是不能保证延迟加载
package com.shufang.create_type.allsingletons;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 可能会产生垃圾对象
* 饿汉式在调用该类的时候装载该实例属性,比较常用
*/
public final class HungrySingleton {
private static HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton() {
System.out.println("inited");
}
public static HungrySingleton getInstance() {
return hungrySingleton;
}
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(10);
for (int i = 0; i < 50; i++) {
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println(HungrySingleton.getInstance());
}
});
}
pool.shutdownNow();
}
}
3 双检锁模式
双检锁模式又称为double-check-lock,能保证延迟加载,也可以保证线程安全
package com.shufang.create_type.allsingletons;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* double-check lock
*/
public class DCLSingleton {
//使用volatile关键字开启线程之间的内存可见性,但是不支持原子性,
private volatile static DCLSingleton dclSingleton;
private DCLSingleton() {
System.out.println("inited");
}
public static DCLSingleton getInstance() {
if (dclSingleton == null) {
synchronized (DCLSingleton.class) {
if (dclSingleton == null) {
dclSingleton = new DCLSingleton();
}
}
}
return dclSingleton;
}
/**
* 测试该创建是否为单例模式
* @param args
*/
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(10);
for (int i = 0; i < 50; i++) {
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println(DCLSingleton.getInstance());
}
});
}
pool.shutdownNow();
}
}
4 静态内部类Holder模式
该模式能实现与双检锁一样的效果,线程安全,且延迟加载
package com.shufang.create_type.allsingletons;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public final class StaticInnerHolderSingleton {
//1 私有化构造器
private StaticInnerHolderSingleton() {
System.out.println("inited");
}
//创建静态内部类,这个成员的初始化也是延迟加载的,只有在调用的时候会装载该内部类
private static class Holder {
static final StaticInnerHolderSingleton INSTANCE = new StaticInnerHolderSingleton();
}
//获取实例
public static StaticInnerHolderSingleton getInstance() {
return Holder.INSTANCE;
}
/**
* 测试实例的创建
* inited,构造器只被调用一次
* com.shufang.create_type.allsingletons.StaticInnerHolderSingleton@be30631
* ......
* @param args
*/
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(10);
for (int i = 0; i < 50; i++) {
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println(StaticInnerHolderSingleton.getInstance());
}
});
}
pool.shutdownNow();
}
}
5 枚举实现单例
通过枚举实现单例,代码简洁,但是目前少用
import java.util.concurrent.Executors;
/**
* 枚举可以实现单例模式,而且代码简介,但是目前不太常用
*/
enum EnumSingleton {
INSTANCE;
//枚举类的构造器默认就是private的
EnumSingleton() {
System.out.println("inited");
}
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(10);
/**
* inited 构造器只被调用了一次
* com.shufang.create_type.allsingletons.EnumSingleton
* com.shufang.create_type.allsingletons.EnumSingleton
*/
for (int i = 0; i < 50; i++) {
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println(EnumSingleton.INSTANCE.getClass().getName());
}
});
}
pool.shutdownNow();
}
}