饿汉式
//饿汉式单例 可能会浪费空间 还没使用的时候已经初始化了
//单例自己实例化自己,构造器必须私有
public class Hungry {
private Hungry(){
}
private final static Hungry hungry = new Hungry();
public static Hungry getInstance(){
return hungry;
}
}
懒汉式DCL (double-check-lock)
//懒汉式单例
public class Lazzy {
private Lazzy(){
System.out.println(Thread.currentThread().getName()+":ok");
}
public volatile static Lazzy lazzy;
//双检锁 DCL
public static Lazzy getInstance(){
if(lazzy == null){
synchronized (Lazzy.class){
if(lazzy == null){
lazzy = new Lazzy();
//new 一个对象非原子性操作,可能会有指令重排的现象
/**
new一个对象的过程
1:分配内存空间
2:执行构造方法,初始化对象
3:把对象指向1的空间
执行顺序123,也有可能顺序是 132;
A线程执行完 1、3 的时候;
B线程进来了,会发现 第一个判断 lazzy != null, 会直接返回一个未初始化完成的对象;
所以单例使用双检锁,要避免当前对象指令重排;使用volatile
*/
}
}
}
return lazzy;
}
// //单线程环境下没问题
// public static Lazzy getInstance(){
// if(lazzy == null){
// //多个线程代码可以同时进入这里
// lazzy = new Lazzy();
// }
// return lazzy;
// }
public static void main(String[] args) {
for (int i=0; i<100; i++) {
new Thread(()->{
Lazzy.getInstance();
}).start();
}
}
public class Holder {
//静态内部类实现单列
private Holder() {
}
public static Holder getInstance(){
return InnerHolder.holder;
}
public static class InnerHolder{
private static final Holder holder = new Holder();
}
}
以上都可以被反射机制破坏 反射可以拿到private的空参构造方法,改变私有权限
//反射!
public static void main(String[] args) throws Throwable {
Lazzy instance = Lazzy.getInstance();
Constructor<Lazzy> declaredConstruct = Lazzy.class.getDeclaredConstructor(null);
declaredConstruct.setAccessible(true);
Lazzy instance2 = declaredConstruct.newInstance();
}
//枚举单例 枚举实质上也是个class是天然的单例, 继承了Enum
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}
枚举为什么不能被反射破坏?
答:jdk的源码有限制,不能以反射的方式创建枚举 Cannot reflectively create enum objects
@CallerSensitive
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, null, modifiers);
}
}
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor; // read volatile
if (ca == null) {
ca = acquireConstructorAccessor();
}
@SuppressWarnings("unchecked")
T inst = (T) ca.newInstance(initargs);
return inst;
}
- 为什么有人说 实现接口是枚举单例的最佳方式??
// 定义单例模式中需要完成的代码逻辑
public interface MySingleton {
void doSomething();
}
public enum Singleton implements MySingleton {
INSTANCE {
@Override
public void doSomething() {
System.out.println("complete singleton");
}
};
public static MySingleton getInstance() {
return Singleton.INSTANCE;
}
}