设计步骤:
1:构造器私有化
2:
含有一个该类的静态变量来保存这个唯一的实例
3:对外提供获取该实例对象的方式
一:饿汉式的几种设计
1:直接创建 这种必须用public来修饰变量 不然外部访问不到
public class Singleton {
public static final Singleton1 INSTANCE = new Singleton();
private Singleton(){
}
}
调用:
Singleton s = Singleton.INSTANCE;
2:枚举
public enum Singleton {
INSTANCE
}
调用:
Singleton s = Singleton.INSTANCE;
3:静态代码块 这种必须用public来修饰变量 不然外部访问不到
public class Singleton {
public static final Singleton3 INSTANCE;
private String info;
static{
try {
Properties pro = new Properties();
pro.load(Singleton3.class.getClassLoader().getResourceAsStream("single.properties"));
INSTANCE = new Singleton3(pro.getProperty("info"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private Singleton(String info){
this.info = info;
}
这是用在特殊场合比如根据某些配置的参数初始化
调用方法
Singleton s = Singleton.INSTANCE;
二:懒汉式的几种设计 privat来修饰变量
1:内部内
/*
* 在内部类被加载和初始化时,才创建INSTANCE实例对象
* 静态内部类不会自动随着外部类的加载和初始化而初始化,它是要单独去加载和初始化的。
* 因为是在内部类加载和初始化时,创建的,因此是线程安全的
*/
public class Singleton {
private Singleton6(){
}
private static class Inner{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return Inner.INSTANCE;
}
}
2:同步锁 线程安全
public class A {
private static A INSTANCE;
private A(){
}
public static synchronized A getInstance() {
if(INSTANCE==null){
INSTANCE=new A();
}
return INSTANCE;
}
}
3:DDL模式(双端检索模式)
public class A {
private static A INSTANCE;
private A(){
}
public static A getInstance() {
if(INSTANCE==null){
synchronized (A.class){
if(INSTANCE==null){
INSTANCE=new A();
}
}
}
return INSTANCE;
}
}
ddl模式可能存在指令重排所以有极低概率发生错误 jmm和jvm知识
指令重排问题略解:INSTANCE=new A(); 分三步完成:
1:memory=allocate(); 内存分配
2:instance(memory);初始化对象
3:instance=memory:指向分配的地址 instance!=null;
指令重排可以打乱执行顺序。
代码优化为:懒汉式最终版
public class A {
private static volatile A INSTANCE;
private A(){
}
public static A getInstance() {
if(INSTANCE==null){
synchronized (A.class){
if(INSTANCE==null){
INSTANCE=new A();
}
}
}
return INSTANCE;
}
}
volatile 关键字可以禁止指令重排 其作用是见性和禁止指令重排但不能保障原子性 下一篇笔记专门记录