zoukankan      html  css  js  c++  java
  • 设计模式-单例模式

    Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”

    1.饿汉式

    package testSingletonUnderMultiThreads;
    
    /**
     * @author zhangdi
     * 饿汉式 : 存在效率和资源占用问题
     */
    public class Singleton_1_MyObject {
    // 饿汉式
    private static Singleton_1_MyObject myObject = new Singleton_1_MyObject();
    
    // private 只有内部才能调用构造器
    private Singleton_1_MyObject() {
        super();
    }
    
    //
    private static Singleton_1_MyObject getInstance() {
        return myObject;
    }
    
    }

    2.懒汉式:存在多线程下的线程安全问题

    package testSingletonUnderMultiThreads;
    
    /**
     * @author zhangdi
     * 懒汉式:存在多线程下的线程安全问题
     */
    public class Singleton_2_MyObject {
        // 定义一个静态变量来记录类的唯一实例,但不初始化
        private static Singleton_2_MyObject myObject;
    
        // 保证只有内部可以调用构造器
        private Singleton_2_MyObject() {
    
        }
    
        public static Singleton_2_MyObject getInstance() {
            if (null != myObject) {
    
            } else {
                myObject = new Singleton_2_MyObject();
            }
            return myObject;
    
        }
    }
    

    3.懒汉式加锁 :可解决多线程下的同步问题,但是存在严重效率问题

    
    /**
     * @author zhangdi
     *  synchronized 加锁 : 可解决多线程下的同步问题,但是存在严重效率问题
     */
    public class Singleton_3_MyObject {
        // 定义一个静态变量来记录类的唯一实例,但不初始化
        private static Singleton_3_MyObject myObject;
    
        // 保证只有内部可以调用构造器
        private Singleton_3_MyObject() {
    
        }
    
        //synchronized保证多线程下的懒汉式是线程安全的,但是问题在于,只有第一次执行时才需要同步,设置好MyObject后都不要同步这个方法了.
        synchronized public static Singleton_3_MyObject getInstance() {
            if (null != myObject) {
    
            } else {
                myObject = new Singleton_3_MyObject();
            }
            return myObject;
    
        }
    }
    

    4.DCL :双重加锁检查 :
    volatile是必须的.

    package testSingletonUnderMultiThreads;
    
    /**
     * @author zhangdi
     * 双重加锁检查 
     */
    public class Singleton_4_MyObject {
        //ps:volatile 保证线程间共享变量的可见性,但不能保证原子性
        //volatile确保myObject被初始化为singleton单例后,多个线程可以正确处理myObject
        private volatile static Singleton_4_MyObject myObject;
    
        private Singleton_4_MyObject() {
        }
    
        private static Singleton_4_MyObject getInstance() {
            //只有第一次才会彻底执行下面的代码
            if (myObject == null) {
                synchronized (Singleton_4_MyObject.class) {
                    //进入区块后,再检查一下,myObject仍为null,才创建实例
                    if(myObject == null){
                        myObject = new Singleton_4_MyObject();
                    }
                }
            }
            return myObject;
    
        }
    }
    

    5 . 使用静态内部类 :静态内部类虽然保证了单例在多线程并发下的线程安全性,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的。
    ps:静态内部类的加载不需要依附外部类,在使用时才加载,而不是在外部类加载时被加载

    package testSingletonUnderMultiThreads;
    
    /**
     * @author zhangdi
     * 使用静态内部类 
     * 静态内部类虽然保证了单例在多线程并发下的线程安全性,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的。
     */
    public class Singleton_5_MyObject {
        //静态内部类的加载不需要依附外部类,在使用时才加载,而不是在外部类加载时被加载
        private static class MyObjectHandler {
            private static Singleton_5_MyObject myObject = new Singleton_5_MyObject();
        }
        //私有构造器是必须的
        private Singleton_5_MyObject() {
        }
    
        public static Singleton_5_MyObject getInstance() {
            return MyObjectHandler.myObject;
    
        }
    }
    

    6.序列化与反序列化的单例模式实现

    package testSingletonUnderMultiThreads;
    
    import java.io.ObjectStreamException;
    import java.io.Serializable;
    
    /**
     * @author zhangdi
     * 序列化与反序列化的单例模式实现
     */
    public class Singleton_6_MyObject implements Serializable {
        private static final long serialVersionUID = 1L;
    
        private static class MyObjectHandler {
            private static Singleton_6_MyObject myObject = new Singleton_6_MyObject();
        }
    
        private Singleton_6_MyObject() {
        }
    
        public static Singleton_6_MyObject getInstance() {
            return MyObjectHandler.myObject;
    
        }
    
        // 该方法在反序列化时会被调用,该方法不是接口定义的方法,有点儿约定俗成的感觉
        protected Object readResolve() throws ObjectStreamException {
            System.out.println("调用了readResolve方法!");
            return MyObjectHandler.myObject;
        }
    
    }
    

    序列化与反序列化测试代码 :

    package testSingletonUnderMultiThreads;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    /**
     * @author zhangdi
     * 序列化与反序列化测试代码
     */
    public class SaveAndReadForSingleton {
    
        public static void main(String[] args) {
            Singleton_6_MyObject singleton = Singleton_6_MyObject.getInstance();
    
            File file = new File("MySingleton.txt");
    
            try {
                FileOutputStream fos = new FileOutputStream(file);
                ObjectOutputStream oos = new ObjectOutputStream(fos);
                oos.writeObject(singleton);
                fos.close();
                oos.close();
                System.out.println(singleton.hashCode());
            } catch (FileNotFoundException e) { 
                e.printStackTrace();
            } catch (IOException e) { 
                e.printStackTrace();
            }
    
            try {
                FileInputStream fis = new FileInputStream(file);
                ObjectInputStream ois = new ObjectInputStream(fis);
                Singleton_6_MyObject rSingleton = (Singleton_6_MyObject) ois.readObject();
                fis.close();
                ois.close();
                System.out.println(rSingleton.hashCode());
            } catch (FileNotFoundException e) { 
                e.printStackTrace();
            } catch (IOException e) { 
                e.printStackTrace();
            } catch (ClassNotFoundException e) { 
                e.printStackTrace();
            }
    
        }
    }
    

    7.static代码块实现单例

    package testSingletonUnderMultiThreads;
    
    /**
     * @author zhangdi
     * 使用static代码块实现单例,也可以保证线程安全性,也有资源占用问题
     */
    public class Singleton_7_MyObject {
        private static Singleton_7_MyObject MyObject = null;
    
        private Singleton_7_MyObject(){}
    
        static {
            MyObject = new Singleton_7_MyObject();
        }
    
        public static Singleton_7_MyObject getInstance() {
            return MyObject;
        }
    
    }
    

    8.枚举实现单例模式

    package testSingletonUnderMultiThreads;
    
    /**
     * @author zhangdi
     * 使用枚举  缺点 : 但是这样写枚举类的实现细节被完全暴露了,违反了“职责单一原则”?
     */
    public enum Singleton_8_MyObject_enum1 {
        singletonFactory;
    
        private MySingleton instance;
    
        private Singleton_8_MyObject_enum1(){//枚举类的构造方法在类加载是被实例化
            instance = new MySingleton();
        }
    
        public MySingleton getInstance(){
            return instance;
        }
    
    }
    
    class MySingleton{//需要获实现单例的类,比如数据库连接Connection
        public MySingleton(){} 
    }
    

    9.完善的枚举类实现单例模式

    package testSingletonUnderMultiThreads;
    
    /**
     * @author zhangdi
     * 完善使用enum枚举实现单例模式:不暴露枚举类的实现细节  
     */
    public class Singleton_9_MyObject_enum2 {
        //不暴露枚举类的实现细节
        private enum MyEnumSingleton {
            singletonFactory;
    
            private MySingleton2 instance;
    
            private MyEnumSingleton() {// 枚举类的构造方法在类加载时被实例化
                instance = new MySingleton2();
            }
    
            public MySingleton2 getInstance() {
                return instance;
            }
        }
    
        public static MySingleton2 getInstance() {
            return MyEnumSingleton.singletonFactory.getInstance();
        }
    
    }
    
    class MySingleton2 {// 需要获实现单例的类,比如数据库连接Connection
        public MySingleton2() {
        }
    }
    
  • 相关阅读:
    委托和异步方法
    线程池_ThreadPool
    委托_deleget
    一步一步实现视频播放器client(二)
    mysql忘记password
    POJ 2456 Aggressive cows (二分 基础)
    Fragment小结
    Cocos2d-x粒子系统
    淘宝数据库OceanBase SQL编译器部分 源代码阅读--解析SQL语法树
    C与C++在形參的一点小差别
  • 原文地址:https://www.cnblogs.com/DiZhang/p/12544984.html
Copyright © 2011-2022 走看看