单例模式学习
程序员文章站
2022-07-06 10:10:21
单例模式学习 1 饿汉式单例模式 还没用就创建了对象,可能会浪费空间 2 懒汉式单例模式 无线程锁 java package main.java.com.yuehun.singleton; / main.java.com.yuehun.singleton @author yuehun Created ......
单例模式学习
1 饿汉式单例模式
package main.java.com.yuehun.singleton; /** * main.java.com.yuehun.singleton * * @author yuehun * created on 2020/4/27. */ // 饿汉式单例模式 public class hungry { private hungry(){} private final static hungry hungry = new hungry(); public static hungry getinstance() { return hungry; } }
- 还没用就创建了对象,可能会浪费空间
2 懒汉式单例模式
无线程锁
package main.java.com.yuehun.singleton; /** * main.java.com.yuehun.singleton * * @author yuehun * created on 2020/4/27. */ // 懒汉式单例模式 public class lazy { private lazy(){ system.out.println(thread.currentthread().getname() + "ok"); } private static lazy lazy = null; public static lazy getinstance() { if (lazy == null) { lazy = new lazy(); } return lazy; } public static void main(string[] args) { for (int i = 0; i < 10; i++) { new thread(lazy::getinstance).start(); } } }
- 单线程下可以,但是多线程不安全
加线程锁
package main.java.com.yuehun.singleton; /** * main.java.com.yuehun.singleton * * @author yuehun * created on 2020/4/27. */ // 懒汉式单例模式 public class lazy { private lazy(){ system.out.println(thread.currentthread().getname() + " ok"); } private volatile static lazy lazy = null; // 双重检测锁模式的懒汉式单例模式, dcl 懒汉式 public static lazy getinstance() { if (lazy == null) { synchronized (lazy.class) { if (lazy == null) { lazy = new lazy(); // 不是一个原子性操作 /** * 1 分配内存空间 * 2 执行构造方法,初始化对象 * 3 把这个对象指向这个空间 * * 可能会发生指令重排!!! */ } } } return lazy; } public static void main(string[] args) { for (int i = 0; i < 10; i++) { new thread(lazy::getinstance).start(); } } }
3 单例不是安全的
使用反射破坏单例模式
- java 里面有个东西叫
反射
- 比如:
package main.java.com.yuehun.singleton; import java.lang.reflect.constructor; /** * main.java.com.yuehun.singleton * * @author yuehun * created on 2020/4/27. */ // 饿汉式单例模式 public class hungry { private hungry(){} private final static hungry hungry = new hungry(); public static hungry getinstance() { return hungry; } public static void main(string[] args) throws exception { hungry instance = new hungry(); constructor<hungry> declaredconstructor = hungry.class.getdeclaredconstructor(null); declaredconstructor.setaccessible(true); hungry instance2 = declaredconstructor.newinstance(); system.out.println(instance); system.out.println(instance2); } }
阻止反射破坏
阻止
反射
的破坏
package main.java.com.yuehun.singleton; import java.lang.reflect.constructor; /** * main.java.com.yuehun.singleton * * @author yuehun * created on 2020/4/27. */ // 饿汉式单例模式 public class hungry { private hungry(){ synchronized (hungry.class) { if (hungry != null) { throw new runtimeexception("不要试图使用反射破坏单例模式"); } } } private final static hungry hungry = new hungry(); public static hungry getinstance() { return hungry; } public static void main(string[] args) throws exception { hungry instance = new hungry(); constructor<hungry> declaredconstructor = hungry.class.getdeclaredconstructor(null); declaredconstructor.setaccessible(true); hungry instance2 = declaredconstructor.newinstance(); system.out.println(instance); system.out.println(instance2); } }
还有一种反射破坏
- 如果两个对象都是通过反射构造的,就不会触发异常
package main.java.com.yuehun.singleton; import java.lang.reflect.constructor; /** * main.java.com.yuehun.singleton * * @author yuehun * created on 2020/4/27. */ // 懒汉式单例模式 public class lazy { // private static boolean flag = false; private lazy() { synchronized (lazy.class) { // if (!flag) // flag = true; // else { if (lazy != null) { throw new runtimeexception("不要试图使用反射破坏单例模式"); // } } } } private volatile static lazy lazy = null; // 双重检测锁模式的懒汉式单例模式, dcl 懒汉式 public static lazy getinstance() { if (lazy == null) { synchronized (lazy.class) { if (lazy == null) { lazy = new lazy(); // 不是一个原子性操作 /** * 1 分配内存空间 * 2 执行构造方法,初始化对象 * 3 把这个对象指向这个空间 * * 可能会发生指令重排!!! */ } } } return lazy; } public static void main(string[] args) throws exception { constructor<lazy> declaredconstructor = lazy.class.getdeclaredconstructor(null); declaredconstructor.setaccessible(true); lazy instance = declaredconstructor.newinstance(); lazy instance2 = declaredconstructor.newinstance(); system.out.println(instance); system.out.println(instance2); } }
又有一种解决方法
package main.java.com.yuehun.singleton; import java.lang.reflect.constructor; /** * main.java.com.yuehun.singleton * * @author yuehun * created on 2020/4/27. */ // 懒汉式单例模式 public class lazy { private static boolean flag = false; private lazy() { synchronized (lazy.class) { if (!flag) flag = true; else throw new runtimeexception("不要试图使用反射破坏单例模式"); } } private volatile static lazy lazy = null; // 双重检测锁模式的懒汉式单例模式, dcl 懒汉式 public static lazy getinstance() { if (lazy == null) { synchronized (lazy.class) { if (lazy == null) { lazy = new lazy(); // 不是一个原子性操作 /** * 1 分配内存空间 * 2 执行构造方法,初始化对象 * 3 把这个对象指向这个空间 * * 可能会发生指令重排!!! */ } } } return lazy; } public static void main(string[] args) throws exception { constructor<lazy> declaredconstructor = lazy.class.getdeclaredconstructor(null); declaredconstructor.setaccessible(true); lazy instance = declaredconstructor.newinstance(); lazy instance2 = declaredconstructor.newinstance(); system.out.println(instance); system.out.println(instance2); } }
破坏者又来了
- 可以通过反射获取到我们设置的这个标志位,在以后每一次创建对象的时候修改它
package main.java.com.yuehun.singleton; import java.lang.reflect.constructor; import java.lang.reflect.field; /** * main.java.com.yuehun.singleton * * @author yuehun * created on 2020/4/27. */ // 懒汉式单例模式 public class lazy { private static boolean flag = false; private lazy() { synchronized (lazy.class) { if (!flag) flag = true; else throw new runtimeexception("不要试图使用反射破坏单例模式"); } } private volatile static lazy lazy = null; // 双重检测锁模式的懒汉式单例模式, dcl 懒汉式 public static lazy getinstance() { if (lazy == null) { synchronized (lazy.class) { if (lazy == null) { lazy = new lazy(); // 不是一个原子性操作 /** * 1 分配内存空间 * 2 执行构造方法,初始化对象 * 3 把这个对象指向这个空间 * * 可能会发生指令重排!!! */ } } } return lazy; } public static void main(string[] args) throws exception { field flag = lazy.class.getdeclaredfield("flag"); flag.setaccessible(true); constructor<lazy> declaredconstructor = lazy.class.getdeclaredconstructor(null); declaredconstructor.setaccessible(true); lazy instance = declaredconstructor.newinstance(); flag.set(instance, false); lazy instance2 = declaredconstructor.newinstance(); system.out.println(instance); system.out.println(instance2); } }
道高一尺,魔高一丈
4 枚举解决
- enum 本身也是一个 class 类
package main.java.com.yuehun.singleton; import java.lang.reflect.constructor; /** * main.java.com.yuehun.singleton * * @author yuehun * created on 2020/4/27. */ public enum enumsingleton { instance; public enumsingleton getinstance() { return instance; } } class test { public static void main(string[] args) throws exception { enumsingleton instance1 = enumsingleton.instance; constructor<enumsingleton> declaredconstructor = enumsingleton.class.getdeclaredconstructor(string.class, int.class); declaredconstructor.setaccessible(true); enumsingleton instance2 = declaredconstructor.newinstance(); system.out.println(instance1); system.out.println(instance2); } }
到此,阻止反射破坏就成功了!
下一篇: 0基础入门前端,会遇到哪些困难?