饿汉式
public class Singleton {
private Singleton() {
}
private static Singleton s = new Singleton();
public static Singleton getIns() {
return s;
}
}
懒汉式DCL
public class Singleton {
private Singleton() {
}
private static Singleton s;
public static Singleton getIns() {
//先判断对象是否已经实例过,没有实例化过才进入加锁代码
if (s == null) {
//类对象加锁
synchronized (Singleton.class) {
if (s == null) {
s = new Singleton();
}
}
}
return s;
}
}
不足 s = new Singleton();不是原子性操作
1、分配内存空间
2、执行构造方法,初始化对象
3、把对象放在内存空间
线程A有可能指令重排 执行顺序132,线程B执行第一个if(s == null) 为假,
直接ruturn s。
进阶
加 volatile
public class Singleton {
private Singleton() {
System.out.println("执行构造");
}
private static volatile Singleton s;
public static Singleton getInstance() {
//先判断对象是否已经实例过,没有实例化过才进入加锁代码
if (s == null) {
//类对象加锁
synchronized (Singleton.class) {
if (s == null) {
s = new Singleton();
}
}
}
return s;
}
public static void main(String[] args) throws Exception {
Singleton instance = Singleton.getInstance();
Constructor<Singleton> declaredConstructors = Singleton.class.getDeclaredConstructor();
declaredConstructors.setAccessible(true);
Singleton o = declaredConstructors.newInstance();
}
}
但可以反射创建对象
public class Singleton {
private Singleton() {
synchronized (Singleton.class) {
if (s != null) {
throw new RuntimeException("禁止反射创建对象");
}
System.out.println("执行构造");
}
}
private static volatile Singleton s;
public static Singleton getInstance() {
//先判断对象是否已经实例过,没有实例化过才进入加锁代码
if (s == null) {
//类对象加锁
synchronized (Singleton.class) {
if (s == null) {
s = new Singleton();
}
}
}
return s;
}
public static void main(String[] args) throws Exception {
Singleton instance = Singleton.getInstance();//重点这里是new的
Constructor<Singleton> declaredConstructors = Singleton.class.getDeclaredConstructor();
declaredConstructors.setAccessible(true);
Singleton o = declaredConstructors.newInstance();
}
}
执行构造
Caused by: java.lang.RuntimeException: 禁止反射创建对象
但是
Constructor<Singleton> declaredConstructors = Singleton.class.getDeclaredConstructor();
declaredConstructors.setAccessible(true);
Singleton o = declaredConstructors.newInstance();
Singleton o2 = declaredConstructors.newInstance();
可以创建两个对象
原因:因为没有通过new 对象,Singleton 类里面的静态变量s一直是null,
if(s != null) 是不起作用的。
修改构造方法
private static volatile boolean a = false;
private Singleton() {
synchronized (Singleton.class) {
if (!a) {
a = true;
System.out.println("执行构造");
} else {
throw new RuntimeException("禁止反射创建对象");
}
}
}
不可以创建两个对象,但是还是可以通过反射修改a的值!!!进而创建两个对象。
public class SingleTon{
private SingleTon(){}
private static class SingleTonHoler{
private static SingleTon INSTANCE = new SingleTon();
}
public static SingleTon getInstance(){
return SingleTonHoler.INSTANCE;
}
}
还是可以通过反射创建对象
枚举单例
enum EnumSingle {
INSTANCE;
public EnumSingle getInstance() {
return INSTANCE;
}
}
Constructor<EnumSingle> declaredConstructors = EnumSingle.class.getDeclaredConstructor();
declaredConstructors.setAccessible(true);
EnumSingle o = declaredConstructors.newInstance();
没有无参构造函数异常
jad.exe 反编译可以看出它确实没有无参构造
Exception in thread "main" java.lang.NoSuchMethodException:
Constructor<EnumSingle> declaredConstructors = EnumSingle.class.getDeclaredConstructor(String.class, int.class);
declaredConstructors.setAccessible(true);
EnumSingle o = declaredConstructors.newInstance("", 1);
不能破坏单例异常
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects