zoukankan      html  css  js  c++  java
  • 双校验 单例类

    package com.example.demo;
    
    import java.io.ObjectStreamException;
    import java.io.Serializable;
    
    public class Person implements Serializable {
    
      private static final long serialVersionUID = 1L;
    
      private volatile static Person singletion;
    
      private Person() {
        if (null == Person.singletion) {
          return;
        } else {
          throw new RuntimeException("单例类不允许二次调用构造函数");
        }
      }
    
      public static Person getSingletion() {
        if (null == Person.singletion) {
          synchronized (Person.class) {
            if (null == Person.singletion) {
              Person.singletion = new Person();
            }
          }
        }
    
        return Person.singletion;
      }
    
    
      private Object readResolve() throws ObjectStreamException {
        return Person.singletion;
      }
    
      protected Object clone() throws CloneNotSupportedException {
        return Person.singletion;
      }
    
    }
    

      volatile 禁止重排序,强制让所有线程缓存失效, 避免了线程获取未构造完全的实例,也避免了线程缓存造成的判 null 问题。构造方法、readResolve、clone 三个方法可以避免反射,反序列化,克隆造成的单例失效。测试代码如下

    public static void main(String[] arg) throws Exception {
        Person person = Person.getSingletion();
        ObjectOutputStream out = new ObjectOutputStream(
            new FileOutputStream("F:\work\IDEA_SPACE\bigdata\demo\src\main\resources\a.txt", true));
        out.writeObject(person);
    
        ObjectInputStream in = new ObjectInputStream(
            new FileInputStream("F:\work\IDEA_SPACE\bigdata\demo\src\main\resources\a.txt"));
        Person person1 = (Person)in.readObject();
    
        log.debug("序列化相等: {}", person == person1);
    
        Person person3 = (Person) person.clone();
        log.debug("克隆相等: {}", person == person3);
    
        Constructor<Person> constructor = Person.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        Person person2 = constructor.newInstance();
    
        log.debug("反射相等: {}", person == person2);
      }
    

      运行结果如下:

    225  [main] DEBUG c.Main - 序列化相等: true
    228  [main] DEBUG c.Main - 克隆相等: true
    Exception in thread "main" java.lang.reflect.InvocationTargetException
    	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    	at com.example.demo.Main.main(Main.java:79)
    Caused by: java.lang.RuntimeException: 单例类不允许二次调用构造函数
    	at com.example.demo.Person.<init>(Person.java:16)
    

      

  • 相关阅读:
    团队博客-会议之初
    5.2 个人作业2
    5.1 如何利用Intellij Idea搭建python编译运行环境
    4.27 python神器——Anaconda的安装与优化配置
    4.26 AlertDialog(对话框)详解
    4.25 xmapp启动mysql出现Error: MySQL shutdown unexpectedly.
    4.24 Android Studio下应用签名的方法以及获取 MD5、SHA1(签名)、SHA256 值
    4.23 2020.2新版本idea创建javaEE web文件
    4.22 Android studio 通过获取验证码用户登陆成功
    4.21 Android 记住密码和自动登录界面的实现(SharedPreferences 的用法)
  • 原文地址:https://www.cnblogs.com/wudeyun/p/13834692.html
Copyright © 2011-2022 走看看