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

    单例模式的几种写法

    1、懒汉式,非线程安全

    private修饰构造方法使得从外部无法直接创建实例(反射除外),但是没有考虑多线程环境。

    public class Singleton {
        //懒汉式-非线程安全
        private static Singleton instance;
        private Singleton() {
    
        }
        public static Singleton getInstance () {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    

    2、懒汉式,线程安全

    加了一个synchronized就可以实现线程安全版本,但是效率太低

    public class Singleton {
        //懒汉式-线程安全
        private static Singleton instance;
        private Singleton() {
    
        }
        public static Singleton getInstance () {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
                return instance;
            }
        }
    }
    

    3、饿汉式

    利用类加载机制在加载类时就创建了实例,但是没有达到lazy-loading的效果。

    public class Singleton {
        //饿汉式
        private static Singleton instance = new Singleton();
        private Singleton() {
    
        }
        public static Singleton getInstance () {
            return instance
        }
    }
    

    变种

    public class Singleton {
        //饿汉式
        private static Singleton instance;
        static {
            instance = new Singleton();
        }
        private Singleton() {
    
        }
        public static Singleton getInstance () {
            return instance;
        }
    }
    

    4、静态内部类

    静态内部类不会在外部类加载时加载,而是在第一次被调用时加载,所以这种方法也是可以达到延迟加载的。

    public class Singleton {
        //饿汉式-静态内部类
        private static Singleton instance;
    
        private static class Holder {
            private static final Singleton instance = new Singleton();
        }
        private Singleton() {
    
        }
        public static Singleton getInstance () {
            return Holder.instance;
        }
    }
    

    5、枚举

    枚举还不是很理解。

    public enum Singleton{
    	INSTANCE;
    }
    

    6、双重检查锁

    还有一个方法就是大名鼎鼎的双重检查锁,可以同时达到线程安全和延迟加载两个要求。

    public class Singleton {
        private static volatile Singleton instance;
    
        private Singleton() {}
    
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
    
            return instance;
        }
    }
    

    开始我不太明白为什么要加volatile关键字修饰instance,后面看到这篇文章:

    为什么双重检查锁要加volatile

    原因是创建对象的过程也不是原子性的,

    instance = new Singleton();
    
    memory = allocate();   //1:分配对象的内存空间
    instance = memory;     //3:设置instance指向刚分配的内存地址
                       //注意,此时对象还没有被初始化!
    ctorInstance(memory);  //2:初始化对象
    

    所以仍有可能被编译器重排序导致多线程环境下创建出多个实例来,而加了volatile之后可以禁止编译器重排序,从而使得创建对象的过程可以在正确的顺序下完成。

  • 相关阅读:
    Android Weekly Notes Issue #428
    《五分钟商学院》个人篇脑图总结笔记(下)
    《五分钟商学院》个人篇脑图总结笔记(上)
    Exceptionless 5.x 无法正常发送邮件的问题解决
    跟玄姐学习技术管理的哲学本质
    观影《八佰》:一边是天堂,一边是地狱
    跟玄姐学习三种架构设计思维模型
    逻辑的工具
    git使用分支文件替换当前分支文件
    认识和理解即构建
  • 原文地址:https://www.cnblogs.com/puyangsky/p/6502112.html
Copyright © 2011-2022 走看看