1.饿汉式
//线程安全 饿汉式 浪费空间
class HungryMan{
private HungryMan(){ System.out.println(Thread.currentThread().getName()); };
private final static HungryMan hungryMan=new HungryMan();
public static HungryMan getInstance(){ return hungryMan; }
}
2.懒汉式
//线程不安全 懒汉式
class LazyMan{
private LazyMan(){ System.out.println(Thread.currentThread().getName()); }
private static LazyMan lazyMan;
public static LazyMan getInstance(){
if(lazyMan==null){
lazyMan=new LazyMan();
}
return lazyMan;
}
}
3.DCL懒汉式
/* 线程安全
双锁校验的懒汉式 DCL懒汉式
指令重排后会出现第二个线程在第一个线程刚实例化之前进入,造成重新实例化对象的问题。
加volatile 避免指令重排
*/
class LazyManAddSync{
private static boolean flag=false;
private LazyManAddSync(){
//有效去除反射
if(flag==false){
flag=true;
}else{
throw new RuntimeException("不要使用反射");
}
//隔离反射 但是如果未实例化对象,直接两次反射,还是会出现反射破坏
/*
synchronized (LazyManAddSync.class){
if(lazyMan!=null){
throw new RuntimeException("不要使用反射");
}
}*/
System.out.println(Thread.currentThread().getName());
}
private volatile static LazyManAddSync lazyMan;
public static LazyManAddSync getInstance(){
if(lazyMan==null){
synchronized (LazyManAddSync.class){
if(lazyMan==null){
/*非原子性操作
分配空间
执行构造方法,初始化对象
把对象指向这个空间
如果指令重排,会导致 23换序,引起异常*/
lazyMan=new LazyManAddSync();
}
}
}
return lazyMan;
}
}
4.静态内部类
//线程安全 静态内部类
class SingletonInnerClass {
private SingletonInnerClass(){System.out.println(Thread.currentThread().getName()); }
public static SingletonInnerClass getInstance(){
return InnerClass.sic;
}
static class InnerClass{
private final static SingletonInnerClass sic=new SingletonInnerClass();
}
}
5.枚举类
//枚举 反射无法破坏枚举
enum EnumSingel{
INSTANCE;
public EnumSingel getInstance(){
return INSTANCE;
}
}
测试类
public class SingleTon {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
System.out.println("测试单例");
for(int i=0;i<10;i++) {
new Thread(()->{
SingletonInnerClass.getInstance();
}).start();
}
//反射可以破坏单例模式
/*
System.out.println("反射");
LazyManAddSync lazyManAddSync=LazyManAddSync.getInstance();
Field flag=LazyManAddSync.class.getDeclaredField("flag");
//修改权限
flag.setAccessible(true);
Constructor<LazyManAddSync> constructor=LazyManAddSync.class.getDeclaredConstructor(null);
constructor.setAccessible(true);
LazyManAddSync lazyManAddSync1=constructor.newInstance();
//修改属性值
flag.setBoolean(lazyManAddSync1,false);
LazyManAddSync lazyManAddSync2=constructor.newInstance();
*/
/* 枚举类 无法反射
Constructor<EnumSingel> constructor=EnumSingel.class.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
EnumSingel enumSingel=constructor.newInstance();*/
}
}