zoukankan      html  css  js  c++  java
  • 多线程十一 单例模式

    本篇博文,将整理关于单例模式(就是让一个类从始至终,只能产生一个对象,而且spring管理的类也全部是单例模式的)与多线程摩擦出的火花

    1 . 懒汉模式(存在线程安全性问题)

    
    public class demo01 {
    
    //要实现单例,肯定不能new对象,因此我们私有化构造函数
    private demo01(){}
    
    //定义一个属于本类的单例对象,每次返回的都是这个对象
    public static demo01  instance = null;
    
    //因为我们没有自己创造出来的对象了,故提供一个静态工厂方法,返回对象的实例
    public static demo01 getInstance(){
        if (instance==null){  //在多线程并发访问的情况下,是存在线程安全问题的
            instance = new demo01();
            return instance;
        }
        return instance;
    }
    }
    
    • 懒汉模式---在使用的时候初始化对象

    2 . 饿汉模式(简单粗暴,实现线程安全)----静态域

    public class demo02 {
    
    //要实现单例,肯定不能new对象,因此我们私有化构造函数
    private demo02(){}
    
    //定义一个属于本类的单例对象,每次返回的都是这个对象
    private static demo02  instance = new  demo02();  // 静态域
    
    //因为我们没有自己创造出来的对象了,故提供一个静态工厂方法,返回对象的实例
    public static demo02 getInstance(){
        return instance;
    }
    }
    
    • 饿汉模式---在类加载的时候初始化对象,

    缺点:

    1 . 如果在构造函数中有过多的其他耗时操作的话,对象的创建会很慢
    2 . 而且对象创建出来了还不一定会马上使用,造成资源的浪费

    使用饿汉模式相应的注意点 :

    1. 对象创建出来以后肯定会被使用
    2. 构造函数没有太多其他处理

    3 . 饿汉模式(简单粗暴,实现线程安全)----静态块

    public class demo05 {
    //要实现单例,肯定不能new对象,因此我们私有化构造函数
    private demo05(){}
    
    //注意点, 下面两段代码是有先后顺序的,假如说颠倒顺序,那么已经初始化的实例也会被重置为null
    public static demo05  instance = null;
    
    static {
        instance = new demo05();
    }
    
    
    //因为我们没有自己创造出来的对象了,故提供一个静态工厂方法,返回对象的实例
    public static demo05 getInstance(){
        return instance;
    }
    
    }
    
    
    • 饿汉模式---在类加载的时候初始化对象,

    缺点:

    1 . 如果在构造函数中有过多的其他耗时操作的话,对象的创建会很慢
    2 . 而且对象创建出来了还不一定会马上使用,造成资源的浪费

    使用饿汉模式相应的注意点 :

    1. 对象创建出来以后肯定会被使用
    2. 构造函数没有太多其他处理

    4. 懒汉模式----使用synchronized实现线程安全

    
    public class demo03 {
    //要实现单例,肯定不能new对象,因此我们私有化构造函数
    private demo03(){}
    
    //定义一个属于本类的单例对象,每次返回的都是这个对象
    public static demo03  instance = null;
    
    
    public static synchronized demo03 getInstance(){
        if (instance==null){
            instance = new demo03();
            return instance;
        }
        return instance;
    }
    
    }
    
    • 加上synchronized 在多线程并发访问的情况下,不再有线程安全问题,但是并不推荐,因为同一时间只有有一个线程进入此静态方法,因此效率低

    5. 懒汉模式---- 双重同步锁单例模式+volatile 实现线程安全

    public class demo04 {
    
    //要实现单例,肯定不能new对象,因此我们私有化构造函数
    private demo04(){}
    
    //定义一个属于本类的单例对象,每次返回的都是这个对象
    public static volatile demo04 instance = null;
    
    
    // 双重同步锁单例模式
    public static  demo04 getInstance(){
        if (instance==null){  // 检测 1
            synchronized (demo04.class){ //锁
                if (instance==null){  //检查 2
                    instance = new demo04();
                }
            }
            return instance;
        }
        return instance;
    }
    
    }
    

    为什么要加上volatile关键字?

    这就要从CPU的指令说起, 当我们执行 

    new demo04();
    

    分下面三步走

    1. memory = allocate(); //分配内存空间
    2. ctorInstance() //初始化对象
    3. instance = memory // 将对象的引用指向刚分配的内存空间

    在单线程的情况下是不会发生任何线程安全问题的,但是! 多线程就会受到 指令重排序的影响, JVM和CPU优化--指令重排序可能出现下面的顺序

    1. memory = allocate(); //分配内存空间
    2. instance = memory // 将对象的引用指向刚分配的内存空间,
    3. ctorInstance() //初始化对象

    这时候双重同步锁单例模式就会出现问题,比如AB两条线程 A运行到指令3却没有真正创建对象 , 然后B去判断instance此时不为空,拿到了instance,一旦调用就会出现问题


    6. 使用枚举实现单例模式 --线程安全

    
    public class demo06 {
    
    private demo06(){}
    
    public static demo06 getInstance(){
            return Singleton.INSTANCE.getDemo06Instance();
    }
    
    //私有的枚举类
    private enum Singleton{
        INSTANCE;
    
        private demo06 demo06Instance;
    
        //JVM保证此构造方法绝对只会调用一次
        Singleton(){
            demo06Instance= new demo06();  //调用外部类私有的构造方法
        }
    
        public demo06 getDemo06Instance(){
            return demo06Instance;
        }
    }
    }
    

    推荐使用这种方法

    • 相对懒汉模式,绝对性的保证的安全问题
    • 相对饿汉模式,当实例在使用的时候才开始初始化
  • 相关阅读:
    ubuntu android jdk问题
    android adb ubuntu问题
    常用命令
    svn info
    TaskRecord分析
    moveTasktoBack 把当前任务放入后台
    WatchDog机制
    双系统安装
    制作安装U盘
    android 小游戏 ---- 数独(二)
  • 原文地址:https://www.cnblogs.com/ZhuChangwu/p/11150356.html
Copyright © 2011-2022 走看看