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之后可以禁止编译器重排序,从而使得创建对象的过程可以在正确的顺序下完成。

  • 相关阅读:
    html更改弹窗样式(原创,转载需声明)
    关于考研的反思
    Android之控件学习
    Android之LinearLayout布局下怎么让按钮固定在底部
    Android中控件属性详细总结(转载)
    毕业设计周记(第四篇)
    毕业设计周记(第三篇)
    毕业设计周记(第二篇)
    毕业设计周记(第一篇)
    Hadoop
  • 原文地址:https://www.cnblogs.com/puyangsky/p/6502112.html
Copyright © 2011-2022 走看看