一. 单例模式
单例模式,属于创建类型的一种常用的软件设计模式。
通过单例模式的方法创建的类在当前进程中只有一个实例
根据需要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例 (来源:百度百科)
简单总结:单例模式就是需要一个私有构造器,一个私有静态类对象
二. 单例模式在单线程下
//懒汉式
private static SingletonDemo instance = null;
private SingletonDemo() {
System.out.println(Thread.currentThread().getName() + "\t 我是构造方法 SingletonDemo");
}
public static SingletonDemo getInstance() {
//判断
if (instance == null) {
instance = new SingletonDemo();
}
}
return instance;
}
调用单例模式:
public static void main(String[] args) {
//单线程
System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
}
运行结果:
三. 单例模式在多线程下
单例模式不变,添加多线程测试
测试代码:
public static void main(String[] args) {
//单线程
//System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
System.out.println("-------------华丽的分割线------------------");
//并发多线程
for (int i = 1; i <= 10; i++) {
new Thread(() -> {
SingletonDemo.getInstance();
}, String.valueOf(i)).start();
}
}
运行结果:
出现了单例模式创建多个对象的情况
四. 解决单例模式在多线程下的问题
解决方式:
1. 使用DCL(Double Check Lock)双端检锁机制
2. 加Volatile关键字
代码加注释:
//懒汉式
/**
* 为什么要加 Volatile关键字?
* 因为 DCL机制还是有点安全隐患的,因为指令重排机制可能会导致其犯错,创建多个对象,
* 所以为了万无一失把指令重排禁止掉。
*
* volatile 禁止指令重排
*/
private static volatile SingletonDemo instance = null;
private SingletonDemo() {
System.out.println(Thread.currentThread().getName() + "\t 我是构造方法 SingletonDemo");
}
/**
* 1. 加 synchronized到方法上解决多线程问题,方案不好,下手太重。
* 2. 使用 DCL(Double Check Lock)双端检锁机制
* DCL: 简单理解就是在加锁前后都检索判断一次
*/
public static /*synchronized*/ SingletonDemo getInstance() {
//判断
if (instance == null) {
//加锁
synchronized (SingletonDemo.class) {
//判断
if (instance == null) {
instance = new SingletonDemo();
}
}
}
return instance;
}
测试代码:
public static void main(String[] args) {
//单线程
//System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
System.out.println("-------------华丽的分割线------------------");
//并发多线程
for (int i = 1; i <= 10; i++) {
new Thread(() -> {
SingletonDemo.getInstance();
}, String.valueOf(i)).start();
}
}
运行结果: