/*实现单例模式:
* 在多线程环境下,对外只存在一个对象
* 1.构造器私有化,防止在外部创建对象
* 2.内部提供私有静态属性:存储对象地址
* 3.提供公共静态方法获取属性*/
饿汉式单例模式:在类创建声明实例的时候,直接初始化实例
public class SingletonDemo {
private static SingletonDemo instance=new SingletonDemo();//类初始化时,对象立即加载
private SingletonDemo(){};//构造器私有
public static SingletonDemo getInstance(){//由于加载类时是天然的线程安全,不需要加synchronized,调用效率高
return instance;
}
}
DCL单例模式(一种懒汉式单例模式,但是调用效率高)
由于编译器优化与JVM底层模型,偶尔会出问题,不建议使用
public class DoubleCheckedLocking {
private static volatile DoubleCheckedLocking instance;//懒汉式,没有new对象,volatile 避免指令重排,因为有可能第一个线程在创建对象的时候,已经返回instance对象地址,其他线程获得的该对象会为空
private DoubleCheckedLocking(){
}
public static DoubleCheckedLocking getinstance(){
if(instance!=null){return instance;}//避免不必要的同步
synchronized (DoubleCheckedLocking.class){if(instance==null){
instance=new DoubleCheckedLocking();
}}
return instance;
}
public static void main(String[] args) {//测试
Thread t1=new Thread(()->{
System.out.println(DoubleCheckedLocking.getinstance());
});
t1.start();
System.out.println(DoubleCheckedLocking.getinstance());
}
}
静态内部类单例模式:
线程安全,调用效率高,延时加载
public class SingletonDemo02 {
private static class SingletonClassInstance{//静态内部类
private static final SingletonDemo02 instance=new SingletonDemo02();
}
public static SingletonDemo02 getInstance(){
return SingletonClassInstance.instance;
}
private SingletonDemo02(){}//构造器私有
}
//静态内部类和非静态内部类一样,都不会因为外部内的加载而加载
//同时静态内部类在使用时才加载,例如调用静态内部类里的变量时
枚举类单例模式:
通过枚举类,避免了通过反射直接调用私有构造器,反序列化漏洞
public enum SingletonDemo03 {
INSTANCE;//这个枚举元素。本身就是SingletonDemo03的单例对象
public void singletonOperation(){}//添加所需操作
}
若不选用枚举类单例模式,用其他类单例模式的时候,可以在私有的构造器加上判断条件,若实例存在则抛出异常来避免反射创建新对象。或者
继承Serializable接口的单例类反序列化时,也会出现问题。可以在类内定义readResolve方法,当反序列化时readobject,会调用该方法直接返回原对象。防止新创建对象。
选用:
单例对象占用资源少,不需要延时加载:选用枚举类单例模式,比饿汉式好
单例对象占用资源多,需要延时加载:选用内部静态类,比懒汉式好