单例模式
单例模式
简介
保证在内存中只有一个实例
饿汉式
public class Single01 {
//类加载初始话
private static final Single01 INSTANCE = new Single01();
//私有构造器
private Single01(){
}
//公开方法
public static Single01 getInstance(){
return INSTANCE;
}
public static void main(String[] args) {
Single01 instance01 = Single01.getInstance();
Single01 instance02 = Single01.getInstance();
System.out.println(instance01 == instance02);
}
}

反射破解
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Single01 {
//类加载初始话
private static final Single01 INSTANCE = new Single01();
//私有构造器
private Single01(){
}
//公开方法
public static Single01 getInstance(){
return INSTANCE;
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Single01 instance01 = Single01.getInstance();
//获得class文件
Class<Single01> single01Class = Single01.class;
//获取无参构造器
Constructor<Single01> constructor = single01Class.getDeclaredConstructor();
//暴力反射
constructor.setAccessible(true);
//反射实例
Single01 single01 = constructor.newInstance();
System.out.println(single01 == instance01);
}
}

懒汉式
线程安全问题
/**
* lazy load
* 虽然按需求初始话,但是有线程安全的问题
* 这里要加上volatile 防止指令重排
*/
public class Single02 {
private static Single02 INSTANCE;
private Single02(){
}
public static Single02 getINSTANCE(){
if (INSTANCE == null){
try {
//测试
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Single02();
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
System.out.println(Single02.getINSTANCE());
}).start();
}
}
}

解决 synchronized
/**
* lazy load
* 虽然按需求初始话,但是有线程安全的问题
* 加上 synchronized 效率会下降
*/
public class Single02 {
private static Single02 INSTANCE;
private Single02(){
}
public synchronized static Single02 getINSTANCE(){
if (INSTANCE == null){
try {
//测试
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Single02();
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
System.out.println(Single02.getINSTANCE());
}).start();
}
}
}
双重检测锁
/**
* 双重检测锁
*/
public class Single03 {
private static Single03 INSTANCE;
private Single03(){
}
public static Single03 getINSTANCE(){
if (INSTANCE == null){
synchronized (Single03.class){
if (INSTANCE == null){
try {
//测试
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Single03();
}
}
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
System.out.println(Single03.getINSTANCE());
}).start();
}
}
}

反射破解
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Single04 {
private static Single04 INSTANCE;
private Single04(){
}
public static Single04 getINSTANCE(){
if (INSTANCE == null){
synchronized (Single04.class){
if (INSTANCE == null){
try {
//测试
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Single04();
}
}
}
return INSTANCE;
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Single04 instance01 = Single04.getINSTANCE();
Class<Single04> single04Class = Single04.class;
Constructor<Single04> constructor = single04Class.getDeclaredConstructor();
constructor.setAccessible(true);
Single04 single04 = constructor.newInstance();
System.out.println(single04 == instance01);
}
}

静态内部类
//开始实现懒加载
public class Single05 {
private Single05(){
}
private static class HolderSingle05{
private static final Single05 INSTANCE = new Single05();
}
//公开方法
public static Single05 getInstance(){
return HolderSingle05.INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(Single05.getInstance());
}).start();
}
}
}

反射破解
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Single05 {
private Single05(){
}
//匿名内部类
private static class HolderSingle05{
private static final Single05 INSTANCE = new Single05();
}
//公开方法
public static Single05 getInstance(){
return HolderSingle05.INSTANCE;
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Single05 instance = Single05.getInstance();
Class<Single05> single05Class = Single05.class;
Constructor<Single05> declaredConstructor = single05Class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Single05 single05 = declaredConstructor.newInstance();
System.out.println(single05 == instance);
}
}
枚举 enum
//枚举类
public enum Single06 {
INSTANCE;
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(Single06.INSTANCE.hashCode());
}
}
}

反射破解
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
//枚举类
public enum Single06 {
INSTANCE;
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
System.out.println(Single06.INSTANCE.hashCode());
Class<Single06> single06Class = Single06.class;;
Constructor<Single06> declaredConstructor = single06Class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Single06 single06 = declaredConstructor.newInstance();
System.out.println(single06.hashCode());
}
}
抛出异常 没有空参构造

这里可以看到如果是枚举的话会报Cannot reflectively create enum objects

通过反编译可以看到构造器其实是有参数的

重新运行一下
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
//枚举类
public enum Single06 {
INSTANCE;
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
System.out.println(Single06.INSTANCE.hashCode());
Class<Single06> single06Class = Single06.class;;
//在构造器传入指定参数
Constructor<Single06> declaredConstructor = single06Class.getDeclaredConstructor(String.class,int.class);
declaredConstructor.setAccessible(true);
Single06 single06 = declaredConstructor.newInstance();
System.out.println(single06.hashCode());
}
}

抛出指定异常 It's ok

浙公网安备 33010602011771号