• GOF-23种设计模式-单例模式


    1.单例模式

    1)饿汉式

    package com.bjsxt.singleton;
    
    public class SingletonDemo1 {
        
        //类初始化时,立即加载这个对象(没有延时加载的优势)。加载类时,天然的是线程安全的!
        private static SingletonDemo1 instance = new SingletonDemo1();  
        
        private SingletonDemo1(){
        }
        
        //方法没有同步,调用效率高!
        public static SingletonDemo1  getInstance(){
            return instance;
        }
        
    }
    package com.bjsxt.singleton;
    
    public class Client {
        
        public static void main(String[] args) {
            SingletonDemo4 s1 = SingletonDemo4.getInstance();
            SingletonDemo4 s2 = SingletonDemo4.getInstance();
            
            System.out.println(s1);
            System.out.println(s2);
        }
    }

    2)懒汉式

    package com.bjsxt.singleton;
    
    public class SingletonDemo2 {
        
        //类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)。
        private static SingletonDemo2 instance;  
        
        private SingletonDemo2(){ //私有化构造器
        }
        
        //方法同步,调用效率低!
        public static  synchronized SingletonDemo2  getInstance(){
            if(instance==null){
                instance = new SingletonDemo2();
            }
            return instance;
        }
    }

    3)双重检查锁

    package com.bjsxt.singleton;
    
    public class SingletonDemo3 { 
    
      private static SingletonDemo3 instance = null; 
    
      public static SingletonDemo3 getInstance() { 
        if (instance == null) { 
          SingletonDemo3 sc; 
          synchronized (SingletonDemo3.class) { 
            sc = instance; 
            if (sc == null) { 
              synchronized (SingletonDemo3.class) { 
                if(sc == null) { 
                  sc = new SingletonDemo3(); 
                } 
              } 
              instance = sc; 
            } 
          } 
        } 
        return instance; 
      } 
    
      private SingletonDemo3() { 
      } 
    }

     4)静态内部类

    package com.bjsxt.singleton;
    
    public class SingletonDemo4 {
        
        private static class SingletonClassInstance {
            private static final SingletonDemo4 instance = new SingletonDemo4();
        }
        
        private SingletonDemo4(){
        }
        
        //方法没有同步,调用效率高!
        public static SingletonDemo4  getInstance(){
            return SingletonClassInstance.instance;
        } 
    }

    5)枚举式

    package com.bjsxt.singleton;
    
    public enum SingletonDemo5 {
        
        //这个枚举元素,本身就是单例对象!
        INSTANCE;
        
        //添加自己需要的操作!
        public void singletonOperation(){
        } 
    }

    其他:

    测试懒汉式单例模式(如何防止反射和反序列化漏洞)

    package com.bjsxt.singleton;
    
    import java.io.ObjectStreamException;
    import java.io.Serializable;
    
    public class SingletonDemo6 implements Serializable {
        //类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)。
        private static SingletonDemo6 instance;  
        
        private SingletonDemo6(){ //私有化构造器
            if(instance!=null){
                throw new RuntimeException();
            }
        }
        
        //方法同步,调用效率低!
        public static  synchronized SingletonDemo6  getInstance(){
            if(instance==null){
                instance = new SingletonDemo6();
            }
            return instance;
        }
        
        //反序列化时,如果定义了readResolve()则直接返回此方法指定的对象。而不需要单独再创建新对象!
        private Object readResolve() throws ObjectStreamException {
            return instance;
        }
        
    }

    测试反射和反序列化破解单例模式

    package com.bjsxt.singleton;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    public class Client2 {
        
        public static void main(String[] args) throws Exception {
            SingletonDemo6 s1 = SingletonDemo6.getInstance();
            SingletonDemo6 s2 = SingletonDemo6.getInstance();
            
            System.out.println(s1);
            System.out.println(s2);
            
            //通过反射的方式直接调用私有构造器
    //        Class<SingletonDemo6> clazz = (Class<SingletonDemo6>) Class.forName("com.bjsxt.singleton.SingletonDemo6");
    //        Constructor<SingletonDemo6> c = clazz.getDeclaredConstructor(null);
    //        c.setAccessible(true);
    //        SingletonDemo6  s3 = c.newInstance();
    //        SingletonDemo6  s4 = c.newInstance();
    //        System.out.println(s3);
    //        System.out.println(s4);
            
            //通过反序列化的方式构造多个对象 
            FileOutputStream fos = new FileOutputStream("d:/a.txt");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(s1);
            oos.close();
            fos.close();
            
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/a.txt"));
            SingletonDemo6 s3 =  (SingletonDemo6) ois.readObject();
            System.out.println(s3);
            
            
        }
    }

    测试多线程环境下五种创建单例模式的效率

    package com.bjsxt.singleton;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutput;
    import java.io.ObjectOutputStream;
    import java.lang.reflect.Constructor;
    import java.util.concurrent.CountDownLatch;
    
    public class Client3 {
    
        public static void main(String[] args) throws Exception {
    
            long start = System.currentTimeMillis();
            int threadNum = 10;
            final CountDownLatch countDownLatch = new CountDownLatch(threadNum);
    
            for (int i = 0; i < threadNum; i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
    
                        for (int i = 0; i < 1000000; i++) {
    //                        Object o = SingletonDemo4.getInstance();
                            Object o = SingletonDemo5.INSTANCE;
                        }
    
                        countDownLatch.countDown();
                    }
                }).start();
            }
    
            countDownLatch.await(); // main线程阻塞,直到计数器变为0,才会继续往下执行!
            long end = System.currentTimeMillis();
            System.out.println("总耗时:" + (end - start));
        }
    }
  • 相关阅读:
    如何区分JS中的this?!
    JavaScript----函数的封装、继承和多态
    正则知识点解读及常用表达式(判断有效数字、手机号邮箱等)
    Java-集合练习5
    输入输出练习
    集合练习5
    集合练习4
    集合练习题2
    Java-集合练习题1
    Java-小练习简单银行程序
  • 原文地址:https://www.cnblogs.com/yuanziren/p/14649945.html
Copyright © 2020-2023  润新知