单例模式
静态内部类
// 静态内部类
public class Holder {
private Holder(){
}
public static class InnerClass {
private static final Holder HOLDER = new Holder();
}
public static Holder getInstance() {
return InnerClass.HOLDER;
}
}
饿汉式(构造器私有,一开始就加载,可能会浪费内存)
// 饿汉式
public class Hungry {
//可能会浪费空间
private byte[] data1 = new byte[1024*1024];
private byte[] data2 = new byte[1024*1024];
private byte[] data3 = new byte[1024*1024];
private byte[] data4 = new byte[1024*1024];
private Hungry(){
}
private final static Hungry HUNGRY = new Hungry();
public static Hungry getInstance(){
return HUNGRY;
}
}
懒汉式(构造器私有,用的时候才加载)
// 懒汉式
public class LazyMan {
private static boolean flag = false;
private LazyMan() {
//System.out.println(Thread.currentThread().getName() + "ok");
synchronized (LazyMan.class) {
if (flag == false) {
flag = true;
}else {
throw new RuntimeException("不要试图通过反射破坏异常");
}
/*if (lazyMan != null) {
throw new RuntimeException("不要试图通过反射破坏异常");
}*/
}
}
private volatile static LazyMan lazyMan;
/*public static LazyMan getInstance(){
if (lazyMan == null) {
lazyMan = new LazyMan();
}
return lazyMan;
}
//单线程可以,多线程不行*/
//多线程并发 有问题
/*public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
lazyMan.getInstance();
}).start();
}
}*/
// 解决:双重检测锁模式的 懒汉式单例 DCL懒汉式
public static LazyMan getInstance() {
if (lazyMan == null) {
synchronized (LazyMan.class) {
if (lazyMan == null) {
lazyMan = new LazyMan(); //不是一个原子性操作
/**
* 1. 分配内存空间
* 2. 执行构造方法,初始化对象
* 3. 把这个对象指向这个空间
* 可能发生指令重排
* private static LazyMan lazyMan; 加volatile
*/
}
}
}
return lazyMan;
}
// 反射破解
public static void main(String[] args) throws Exception {
//LazyMan instance = LazyMan.getInstance();
Field flag = LazyMan.class.getDeclaredField("flag");
flag.setAccessible(true); //破坏私有权限
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan instance = declaredConstructor.newInstance(); //还是被破解,用标志位加密
flag.set(instance, false);
LazyMan instance1 = declaredConstructor.newInstance();
//打印两个单例的实现类,不一样
System.out.println(instance);
System.out.println(instance1);
}
}
单例不安全, 因为反射
枚举
enum本身是一个class类
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws Exception {
EnumSingle instance1 = EnumSingle.INSTANCE;
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class, int.class);
declaredConstructor.setAccessible(true);
EnumSingle instance2 = declaredConstructor.newInstance();
System.out.println(instance1);
System.out.println(instance2);
}
}