zoukankan      html  css  js  c++  java
  • 单例的几种方式,以及如何破坏单例,使用枚举保护单例;

    1、基础入门单例:

     1 public class Singleton {
     2     private Singleton(){
     3         System.out.println("Singleton 初始化的过程");
     4     }
     5     
     6     private static Singleton singleton = null;
     7     
     8     /**@Description: 单例同步控制,方法加syn
     9      * @return
    10      * @author BIQI  2017年12月20日下午3:10:23
    11      * @return Singleton  @throws
    12      */
    13     public static synchronized Singleton getSingleton1(){
    14         if (null == singleton ) {
    15             singleton = new Singleton();
    16         }
    17         return singleton;
    18     }
    19     
    20     /**@Description: 单例同步控制2,使用ReentrantLock锁
    21      * @return
    22      * @author BIQI  2017年12月20日下午3:14:16
    23      * @return Singleton  @throws
    24      */
    25     public static Singleton getSingleton2(){
    26         ReentrantLock lock = new ReentrantLock();
    27         lock.lock();
    28         if (null == singleton ) {
    29             singleton = new Singleton();
    30         }
    31         lock.unlock();
    32         return singleton;
    33     }
    34     
    35     /**@Description: 双重检测机制  DCL(Double CheckLock)实现单例
    36      * @return
    37      * @author BIQI  2017年12月20日下午3:15:31
    38      * @return Singleton  @throws
    39      */
    40     public static  Singleton getSingleton3(){
    41         //第一重检测
    42         if (null == singleton ) {
    43             synchronized (singleton) {
    44                 //第二重检测
    45                 if (null == singleton) {
    46                     singleton = new Singleton();
    47                 }
    48             }
    49         }
    50         return singleton;
    51     }
    52 }

    2、单例的进阶,控制指令重排

    public class Singleton2 {
        
        /*
         * 指令重排是 
              比如java中简单的一句 instance = new Singleton,会被编译器编译成如下JVM指令:
            memory =allocate();    //1:分配对象的内存空间 
            ctorInstance(memory);  //2:初始化对象 
            instance =memory;     //3:设置instance指向刚分配的内存地址 
            
            但是这些指令顺序并非一成不变,有可能会经过JVM和CPU的优化,指令重排成下面的顺序:
            
            memory =allocate();    //1:分配对象的内存空间 
            instance =memory;     //3:设置instance指向刚分配的内存地址 
            ctorInstance(memory);  //2:初始化对象 
         */
        
        private Singleton2() {
            System.out.println("Singleton 初始化的过程");
        }  
        
        //volatile 阻止变量访问前后指令的重排,保证指令执行顺序
        private volatile static Singleton2 singleton = null;  //单例对象
        
        //静态工厂方法
        public static Singleton2 getInstance() {
            if (singleton == null) {      //双重检测机制
                synchronized (Singleton.class){  //同步锁
                    if (singleton == null) {     //双重检测机制
                        singleton = new Singleton2();
                        }
                    }
                }
            return singleton;
        }
    }

    3、classloader的加载机制来实现懒加载单例实现

     1 public class Singleton3 {
     2     /**
     3      * 1.从外部无法访问静态内部类LazyHolder,
     4      * 只有当调用Singleton.getInstance方法的时候,
     5      * 才能得到单例对象INSTANCE。
     6      * 2.INSTANCE对象初始化的时机并不是在单例类Singleton被加载的时候,
     7      * 而是在调用getInstance方法,使得静态内部类LazyHolder被加载的时候。
     8      * 因此这种实现方式是利用classloader的加载机制来实现懒加载,
     9      * 并保证构建单例的线程安全。
    10      * 
    11      */
    12     private static class LazyHolder {
    13         private static final Singleton3 INSTANCE = new Singleton3();
    14     }
    15     private Singleton3 (){}
    16     public static Singleton3 getInstance() {
    17         return LazyHolder.INSTANCE;
    18     }
    19 }

    4、最推荐的单例,使用枚举,因为枚举的特性以及实现方式(这里不阐述);

        常量实际是被编译为静态变量,Java中静态变量都是存储在Method Area

    1 public enum SingletonEnum1 {
    2     
    3     INSTANCE();
    4     
    5     SingletonEnum1(){
    6         System.out.println("SingletonEnum1 初始化的过程");
    7     }
    8 }

    5、如何破坏单例模式,如果不适用枚举的话;

     1 /**
     2  * @Title: BreakSingleton.java
     3  * @Description: 破坏单例的情况,后面通过枚举去破解
     4  *  
     5  * @author BIQI IS BEST
     6  * @date 2017年12月20日 下午3:27:39
     7  * @version V1.0
     8  */
     9 public class BreakSingleton {
    10 
    11     public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    12         // TODO Auto-generated method stub
    13         
    14         //获得构造器
    15         Constructor con = Singleton.class.getDeclaredConstructor();
    16         //设置为可访问
    17         con.setAccessible(true);
    18         //构造两个不同的对象
    19         Singleton singleton1 = (Singleton)con.newInstance();
    20         Singleton singleton2 = (Singleton)con.newInstance();
    21         //验证是否是不同对象
    22         System.out.println(singleton1.equals(singleton2));
    23         
    24         //枚举类的获得
    25         SingletonEnum1 singletest1 =SingletonEnum1.INSTANCE;
    26         SingletonEnum1 singletest2 =SingletonEnum1.INSTANCE;
    27         System.out.println(singletest1.equals(singletest2));
    28     }
    29 }
  • 相关阅读:
    bzoj 4007
    bzoj 2190
    bzoj 2186
    bzoj 2005
    bzoj 2721
    bzoj 1951
    CF919F
    CF1005F
    CF1019C
    bitset用法详解
  • 原文地址:https://www.cnblogs.com/xiebq/p/8124410.html
Copyright © 2011-2022 走看看