单线程下 单例模式
package top.mgy.ebook;
/**
* 单机版 单例模式
*/
public class SingletonDome {
private static SingletonDome instance = null;
private SingletonDome(){
System.out.println("我被创建了:"+Thread.currentThread().getName());
}
public static SingletonDome getInstance(){
if(instance == null){
instance = new SingletonDome();
}
return instance;
}
public static void main(String[] args) {
System.out.println(SingletonDome.getInstance() == SingletonDome.getInstance());
System.out.println(SingletonDome.getInstance() == SingletonDome.getInstance());
System.out.println(SingletonDome.getInstance() == SingletonDome.getInstance());
}
}
在多线程情况下,将会被创建多个实例
for (int i = 0; i < 50; i++) {
new Thread(()->SingletonDome.getInstance(),i+"").start();
}
多线程下单例模式
这种方式仍然存在问题,就是指令重排,在创建一个对象时,需要进行 1 分配对象内存-》2 初始化对象-》3 设置 instance指向该内存地址;由于步骤2和3没有数据依懒性,所以编译器或者CPU可以进行指令重排,于是可能上面的步骤变为 1,3,2,这样将会导致对象还没有创建就已经将 instance指向该内存空间了,后面的线程在判断发现instance不为空,会直接返回未初始化的对象地址。所以需要加 volatile 保证指令不被重排
/**
* 多线程 单例模式
*/
public class SingletonDome {
private static SingletonDome instance = null;
private SingletonDome(){
System.out.println("我被创建了:"+Thread.currentThread().getName());
}
//DCL 使用双端检查机制 即在加锁前后都进行判断
public static SingletonDome getInstance(){
if(instance == null){
synchronized (SingletonDome.class){
if(instance == null){
instance = new SingletonDome();
}
}
}
return instance;
}
public static void main(String[] args) {
// System.out.println(SingletonDome.getInstance() == SingletonDome.getInstance());
// System.out.println(SingletonDome.getInstance() == SingletonDome.getInstance());
// System.out.println(SingletonDome.getInstance() == SingletonDome.getInstance());
for (int i = 0; i < 50; i++) {
new Thread(()->SingletonDome.getInstance(),i+"").start();
}
}
}