中煤建设协会网站竞价推广账户竞价托管费用
- 作者: 五速梦信息网
- 时间: 2026年04月20日 03:48
当前位置: 首页 > news >正文
中煤建设协会网站,竞价推广账户竞价托管费用,免费html网站模板,苏州公司做网站设计模式包含很多#xff0c;但与面试相关的设计模式是单例模式#xff0c;单例模式的写法有好几种#xff0c;我们主要学习这三种—饿汉式单例#xff0c;懒汉式单例、登记式单例,这篇文章我们主要学习饿汉式单例 单例模式#xff1a; 满足要点#xff1a; 私有构造 …设计模式包含很多但与面试相关的设计模式是单例模式单例模式的写法有好几种我们主要学习这三种—饿汉式单例懒汉式单例、登记式单例,这篇文章我们主要学习饿汉式单例 单例模式 满足要点 私有构造 提供静态全局变量 提供专门访问静态全局变量的方法饿汉式实现 实现类 import java.io.Serializable;//1饿汉式 public class Singleton1 implements Serializable {//私有构造private Singleton1(){System.out.println(private Singleton1);}//提供静态的全局变量private static final Singleton1 INSTANCE new Singleton1();//相对于懒汉式是提前创建的//提供专有的方法去获得静态变量public static Singleton1 getInstance(){return INSTANCE;}public static void otherMethod(){System.out.println(otherMethod());} }测试类 public class Test_Singleton1 {public static void main(String[] args) {//触发当前类的加载链接–导致该类的初始化操作被创建当我们调用otherMethod()方法时,该类已经被创建因为在输出的内容中包含该类私有构造中的内容Singleton1.otherMethod();System.out.println();//下面我们调用getInstance()方法时得到的对象为上述已经创建好的对象System.out.println(Singleton1.getInstance());System.out.println(Singleton1.getInstance());} }输出 private Singleton1 otherMethod()Singleton17ef20235 Singleton17ef20235由于上述的单例我们实现的是Serializable接口因此很容易被破坏常见的破坏方式有以下几种 反射破坏单例 import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException;public class Test_Singleton1 {Singleton1.otherMethod();System.out.println();System.out.println(Singleton1.getInstance());System.out.println(Singleton1.getInstance());、//反射破坏单例reflection(Singleton1.class);}private static void reflection(Class? classz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//通过getDeclaredConstructor获得私有构造Constructor? constructorclassz.getDeclaredConstructor();//通过setAccessible使得私有的构造方法也可以被使用constructor.setAccessible(true);//使用newInstance创建新的对象System.out.println(反射创建实例:constructor.newInstance());} }输出 private Singleton1 otherMethod()Singleton17ef20235 Singleton17ef20235 private Singleton1 反射创建实例:Singleton115aeb7ab经过反射操作的Singleton1已经不是单例了由于getInstance和反射创建的对象并不是同一个一个类有两个对象并不符合单例 newInstance()和new()区别 创建对象的方式不同newInstance()是实用类的加载机制new()则是直接创建一个类newInstance创建类是这个类必须已经加载过且已经连接Class.forName(“A”)这个过程new创建类是则不需要这个类加载过 newInstance实际上是把new这个方式分解为两步,首先调用class的加载方法加载某个类然后实例化这样做的好处体现在我们可以在调用class的静态加载方法forName时获得更好的灵活性 newInstance 是弱类型(GC是回收对象的限制条件很低容易被回收)、低效率、只能调用无参构造 new是强类型GC不会自动回收只有所有的指向对象的引用被移除是才会被回收若对象生命周期已经结束但引用没有被移除经常会出现内存溢出 预防反射破坏单例 解决方法 在私有构造中加入如下代码当单例对象已经被创建过时则直接抛出异常 if(INSTANCE!null) {throw new RuntimeException(单例对象不能重复创建); }测试结果如下 对象只被创建了一次第二次通过反射创建对象时直接抛出异常 反序列化破坏单例 import java.io.; import java.lang.reflect.InvocationTargetException;public class Test_Singleton1 {public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException, ClassNotFoundException {Singleton1.otherMethod();System.out.println();System.out.println(Singleton1.getInstance());System.out.println(Singleton1.getInstance());//反序列化破坏单例serializable(Singleton1.getInstance());}private static void serializable(Object instance) throws IOException, ClassNotFoundException {ByteArrayOutputStream byteArrayOutputStreamnew ByteArrayOutputStream();//创建输出流对象ObjectOutputStream objectOutputStreamnew ObjectOutputStream(byteArrayOutputStream);//通过writeObject将获取到的对象转变为字节流objectOutputStream.writeObject(instance);//创建文件输入流对象//toByteArray()方法是将一个ByteArrayOutputStream对象转换为byte字符数组返回ObjectInputStream objectInputStreamnew ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));//通过readObject将转变后的字节流还原成对象System.out.println(反序列化创建实例objectInputStream.readObject());} }输出 这种反序列化的过程不仅可以产生新的对象且并不实现构造方法 private Singleton1 otherMethod()Singleton17ef20235 Singleton17ef20235 反序列化创建实例Singleton11a93a7ca预防反序列化破坏单例 解决办法为在Singleton1类中重写readResolve方法使得它的返回值为初始创建的instance对象而不是通过反序列化再创建新的对象 public Object readResolve(){return INSTANCE;}Unsafe破坏单例 unsafe(Singleton1.class);private static void unsafe(Class? clazz) throws InstantiationException {Object o UnsafeUtils.getUnsafe().allocateInstance(clazz);System.out.println(Unsafe 创建实例: o); }Unsafe是JDK内置的一个类它并不是Java标准类一般的开发者不会涉及此类的开发它不需要调用构造函数且这种破坏方式目前没有解决的办法 枚举类实现饿汉式单例 enum_Sington类 public enum enum_Sington {INSTANCE;private enum_Sington(){System.out.println(private enum_Sington());}public static enum_Sington getInstance(){return INSTANCE;}Overridepublic String toString() {return getClass().getName()Integer.toHexString(hashCode());}public static void otherMethod(){System.out.println(otherMethod());} }测试类 import java.io.; import java.lang.reflect.InvocationTargetException; public class Test_Sington2 {//单例模式-饿汉式public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException,IOException, ClassNotFoundException {enum_Sington.otherMethod();System.out.println();System.out.println(enum_Sington.getInstance());System.out.println(enum_Sington.getInstance());} }输出 private enum_Sington() otherMethod()enum_Sington7ef20235 enum_Sington7ef20235然而对于枚举类反序列化并不能将其破坏掉验证如下 在上述的测试类中加入反序列的代码如下所示 serializable(enum_Sington.getInstance());private static void serializable(Object instance) throws IOException, ClassNotFoundException {ByteArrayOutputStream byteArrayOutputStreamnew ByteArrayOutputStream();ObjectOutputStream objectOutputStreamnew ObjectOutputStream(byteArrayOutputStream);//通过writeObject将获取到的对象转变为字节流objectOutputStream.writeObject(instance);ObjectInputStream objectInputStreamnew ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));//通过readObject将转变后的字节流还原成对象System.out.println(反序列化创建实例objectInputStream.readObject());}输出 private enum_Sington() otherMethod()enum_Sington7ef20235 enum_Sington7ef20235 反序列化创建实例enum_Sington7ef20235通过输出结果我们会发现反序列化创建的对象和上述枚举类创建的对象是同一个 那么反射可以破坏吗 验证如下 reflection(enum_Sington.class); private static void reflection(Class? classz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//通过getDeclaredConstructor获得私有构造Constructor? constructorclassz.getDeclaredConstructor();//通过setAccessible使得私有的构造方法也可以被使用constructor.setAccessible(true);System.out.println(反射创建实例:constructor.newInstance());}newInstance实例化对象只能调用无参构造方法如果重写了一个带参构造方法想要使用newInstance则必须指定一个无参构造方法否则会报初始化错误 懒汉式实现 import java.io.Serializable;public class Singleton3 implements Serializable {private Singleton3(){System.out.println(private Singleton3());}private static Singleton3 INSTACE null;//开始将其置为null当要使用它时才创建该对象public static Singleton3 getInstance() {if (INSTACE null) {INSTACE new Singleton3();}return INSTACE;}public static void otherMethod() {System.out.println(otherMethod());} } class Test_Singleton1 {public static void main(String[] args) {//INSTACE对象此时还不会被创建Singleton3.otherMethod();System.out.println();//当调用getISTACE方法时INSTACE对象才会被创建System.out.println(Singleton3.getInstance());System.out.println(Singleton3.getInstance());} }otherMethod()private Singleton3() Singleton37ef20235 Singleton37ef20235但懒汉式会出现一个问题也就是不加线程的保护下多个线程都可以调用getINSTACE方法那么当多线程调用这个方法时就会出现下述问题 线程1首次调用getINSATCE方法发现INSTACE是null没有被创建因此进行创建当线程1执行到if语句中的代码时线程二也调用该方法假设此时线程1还没有完成将刚创建好的对象赋值给INSTACE的这个操作就会出现当线程2调用该方法时INSTACE显示还是为null它也会创建新的INSTACE对象此时就不能被称为是单例了 这就是我们在多线程环境下执行单例存在的问题那么该如何解决呢 给getInstance方法加安全保护也就是用sychronized进行修饰其原理就是给该方法加锁 当加锁后的运行过程如下所示 当线程2获得使用权后进入该方法发现INSTCE不为null则不进行该对象的创建直接返回前面线程1已经创建好的INSTCE对象这样就能有效的避免多线程下单例模式的正确运行 但这样做的性能并不是最好的原因是我们加锁的目的就是为了防止INSTACE被多次创建这样虽然能够解决首次仅由一个线程创建该对象但当下次调用该方法的时候加锁似乎没什么意义因为对象已经被创建出来了 我们理想的目标是首次调用该方法加锁而后续调用不加锁 优化方法——使用双检锁 注意 使用双检锁的INSTACE对象必须用volatile关键字修饰主要利用内存屏障保证有序性在多线程下防止发生指令重排序 private static volatile Singleton3 INSTACE null;内部类实现懒汉式单例 发生在懒汉式中的多线程安全问题并没有出现在饿汉式实现单例中原因是我们将其INSTACE对象的创建赋值给了static修饰的变量而被static修饰的代码最终都会放在静态代码块中执行而静态代码块中的线程安全并不需要我们去考虑java虚拟机会帮我们保证其安全 那我们只需想办法将懒汉式中的INSTACE对象创建过程放在一个静态的代码块中即可如下所示 内部类也是符合懒汉式的特征如果内部类没有被使用那么类的加载链接初始化过程也不会发生自然写在其中的INSTACE也不会被重复创建那么什么时候会使用到它呢 就是调用getInstace方法的时候因此我们只需要将类的使用过程写在getInstace方法中 import java.io.Serializable;public class Singleton3 implements Serializable {private Singleton3(){System.out.println(private Singleton3());}private static class Holder {static Singleton3 INSTACEnew Singleton3();}public static Singleton3 getInstance(){return Holder.INSTACE;}public static void otherMethod() {System.out.println(otherMethod());} } class Test_Singleton1 {public static void main(String[] args) {//触发当前类的加载链接–导致该类的初始化操作被创建当我们调用otherMethod()方法时,该类已经被创建因为在输出的内容中包含该类私有构造中的内容Singleton3.otherMethod();System.out.println();//下面我们调用getInstance()方法时得到的对象为上述已经创建好的对象System.out.println(Singleton3.getInstance());System.out.println(Singleton3.getInstance());} }上述使用内部类的懒汉式也正是我们所推荐的不仅符合懒汉式的特征而且可以保证线程安全
- 上一篇: 中煤第一建设公司网站只选设计师的网站
- 下一篇: 中南建设网官方网站北京企业
相关文章
-
中煤第一建设公司网站只选设计师的网站
中煤第一建设公司网站只选设计师的网站
- 技术栈
- 2026年04月20日
-
中煤第三建设集团网站网站建设合同以及服务条款
中煤第三建设集团网站网站建设合同以及服务条款
- 技术栈
- 2026年04月20日
-
中铝长城建设有限公司网站中山市建设局网站窗口电话
中铝长城建设有限公司网站中山市建设局网站窗口电话
- 技术栈
- 2026年04月20日
-
中南建设网官方网站北京企业
中南建设网官方网站北京企业
- 技术栈
- 2026年04月20日
-
中宁网站建设公司网站 类库
中宁网站建设公司网站 类库
- 技术栈
- 2026年04月20日
-
中诺建设集团有限公司网站北京公司模板网站
中诺建设集团有限公司网站北京公司模板网站
- 技术栈
- 2026年04月20日
