• java 单例模式


    一、定义及应用

      单例模式,是一种常用的软件设计模式,在使用这个设计模式时,单例对象的类要保证只有一个实例存在。

      许多时候整个系统只需要有一个全局对象,这样有利于我们协调整个系统的行为。比如服务器程序中,服务器程序的配置信息存储在一个文件中,使用一个单例对象同意读取,服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了复杂环境下的配置管理。同样,线程池、连接池也是通过单例模式进行管理。

    二、实现

    1)、两懒汉方式

    public class Singleton{//非线程安全
      private static Singleton instance;
      private Singleton(){};
      public static Singleton getInstance(){
         if(instance==null){
             instance=new singleton();
       }
         return instance;
      }  
    }
    
    public class Singleton{//线程安全
      private static Singleton instance;
      private Singleton(){};
      public static synchronized Singleton getInstance(){
         if(instance==null){
             instance=new singleton();
       }
         return instance;
      }  
    }

    2)、饿汉方式

    public class Singleton{
      private static final Singleton instance=new Singleton();
      private Singleton(){};
      public static Singleton getInstance(){
        return instance;
      }
    }

    3)、内部类

    public class Singleton{//懒加载 线程安全
      private static class SingletonHolder{
        private static final Singlton instance=new Singleton();
      }
      private Singleton(){};
      public static Singleton getInstance(){
        return SingletonHolder.instance;
      }
    }

    4)、枚举

    public enum Singleton{
      INSTANCE;
      //....other function    
    }

      写枚举单例的方式,它可能包含实例变量和实例方法,但是简单来说我什么都没用,需要注意的是如果你使用实例方法,你就需要确保方法的线程安全性,避免它会影响对象的状态。通常情况下枚举里面创建实例是线程安全的,但是其它的方法就需要编程者自己去考虑了。

    5)、双校验

    public class Singleton{
      private volatile static Singleton instance;//volatile关键字保证当instance变量被初始
      private Singleton(){};//化Singleton实例后,多个线程正确的处理instance变量
      public static Singleton getInstance(){
        if(instance==null){
          synchronize(Singleton.class){
            if(instance == null){
              instance = new Singleton();
            }
          }
        }
        return instance;
      }
    }

    三、防止破坏单例模式

    1、阻止clone()方法创建单例实例的另一个实例

      1)override clone()方法

        protected Object clone() throws CloneNotSupportedException{
            throw new CloneNotSupportedException();
        }

      2)一个是单例类一定要是final的,这样用户就不能继承它了

    如果有其他方法可以交流交流!

    2、防止反射破坏

    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    public class Singletom {
    
        private static final Singletom instance=new Singletom();
        private Singletom(){};
        public static Singletom getInstance(){
            return instance;
        }
        
        public static void main(String [] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException{
            Class<Singletom> clazz = Singletom.class;
            Constructor<Singletom> constructor = clazz.getDeclaredConstructor();
            
            constructor.setAccessible(true);
            System.out.println(Singletom.instance == constructor.newInstance());
        }
    }
    View Code

    打印出 false

    解决方法:没找到答案 期望交流

    3、防止系列化破坏

    破坏代码:

    public class Singleton implements Serializable{
        private static final long serialVersionUID = 1L;
        private static final Singleton instance=new Singleton();
        private Singleton(){};
        public static Singleton getInstance(){
            return instance;
        }
        public static void main(String [] args){
         // 支持java.io.Serializable的对象都可以写入流中 ByteArrayOutputStream bos
    =new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(Singleton.instance); // 根据字节流生成对象 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); Singleton singleton = (Singleton) ois.readObject(); System.out.println(Singleton.instance == singleton); } }

    解决办法:

    //在类中实现readResovle方法
        private Object readResolve(){
            return instance;
        }

    输出为true

     4、防止不同类装载器破坏

    如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。例如一些servlet容器对每个servlet使用完全不同的类装载器,这样的话如果有两个servlet访问一个单例类,它们就都会有各自的实例。

    解决办法:

        private static Class getClass(String classname)throws ClassNotFoundException {     
              ClassLoader classLoader = Thread.currentThread().getContextClassLoader();     
              if(classLoader == null)     
                 classLoader = Singleton.class.getClassLoader();     
              return (classLoader.loadClass(classname));     
        }

    参考:http://www.oracle.com/technetwork/articles/java/singleton-1577166.html

  • 相关阅读:
    缩略图架构实现
    基于GDAL实现的PCA变换(主成分分析)
    【OpenGL】GLSL中的函数和子程序(subroutines)
    【OpenGL】关于OpenGL中Bind函数的理解
    使用MTL库求解矩阵特征值和特征向量
    C#键盘事件列表
    C#用 SendKyes 结合 Process 或 API FindWindow、SendMessage(PostMessage) 等控制外部程序
    什么是句柄
    在DLL中产生对话框的方法一(Win32 DLL)
    C# 四舍五入
  • 原文地址:https://www.cnblogs.com/tutar/p/3655370.html
Copyright © 2020-2023  润新知