-
饿汉式、懒汉式区别
1.饿汉式:在程序启动或单件模式类被加载的时候,单件模式实例就已经被创建。
2.懒汉式:当程序第一次访问单件模式实例时才进行创建。
3.懒汉式时间换空间,节约内存空间;饿汉式空间换时间,节省运行时间
4.饿汉式是线程安全的,懒汉式是存在线程安全问题 -
饿汉式为什么是线程安全的
因为虚拟机保证只会装载一次,在装载类的时候是不会发生并发的;而懒汉式在创建对象的时候在多线程环境下,其它线程有可能已经创建了对象,存在线程安全问题 -
线程单例、进程单例、集群单例
单例模式是进程程单一;ThreadLocal 可以实现线程单一;需要借助外部存储媒介来实现集群单一 -
静态内部类为什么能保证单例和线程安全
外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化INSTANCE,故而不占内存。只有当getInstance()方法第一次被调用时,才会去初始化INSTANCE,第一次调用getInstance()方法会导致虚拟机加载内部类,在内存空间创建一个唯一的INSTANCE,这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化 -
为什么枚举类是最好最安全的单例
反射和序列化可以破坏单例
1.枚举不可以被放射(具体查看放射代码)
2.枚举序列化有专门的处理方法(具体查看ObjectInputStream代码) -
Spring 是用哪种方式实现单例的
由于单例模式私有构造所有不能被继承,Spring为了让单例可以继承,采用了单例注册表的方式实现单例模式,原理使用HashMap实现注册表 -
代码
//饿汉式
public class Singletion{
private statice Singletion instance = new Singletion();
private Singletion(){}
public static Singletion getInstance (){
return instance;
}
}
//懒汉式
public class Singletion{
public static Singletion getInstance(){
//volatile 防止指令重排
private volatile static Singleion instance = null;
private Singletion(){}
//双重检查加锁 先检查对象是否为为null 再进行同步,提高效率,避免每次创建对象都同步
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
instance = new Singletion();
}
return instance;
}
}
//静态内部类
public class Singleton(){
private Singleton(){}
private static class SingletonInner {
private static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonInner.instance;
}
}
//枚举
public enum Singleton{
INSTANCE;
public void method(){
//具体业务逻辑
}
}
public class Main{
public static void main(String[] args){
Singleton.INSTANCE.method();
}
}
//反射攻击
public class SingletionAttack(){
public static void main(String[] args) throws Exception{
Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
//取消检查Java语言控制权限 例如:private
constructor.setAccessible(true);
Singleton singleton = constructor.newInstance();
Singleton singleton1 = constructor.newInstance();
System.out.println(singleton1 == singleton);
}
}
//序列化攻击
public static void main(String[] args) throws Exception {
ObjectOutputStream outputStream = new ObjectOutputStream(
new FileOutputStream("fileName")
);
Singleton instance = Singleton.getInstance();
outputStream.writeObject(instance);
ObjectInputStream inputStream = new ObjectInputStream(
new FileInputStream("fileName")
);
Singleton instance2 = (Singleton) inputStream.readObject();
System.out.println(instance == instance2);
}
- 源码中的案例
//可以获得系统环境变量、java版本号、运行其它程序的文件
public class Runtime {
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
private Runtime() {}
}