博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
单例模式
阅读量:3934 次
发布时间:2019-05-23

本文共 2525 字,大约阅读时间需要 8 分钟。

 

单例模式Table of Contents

* 1. 饿汉模式
* 2. 懒汉模式以及演进
* 3. 静态内部类方式
* 4. ENUM方式

为什么:

*
逻辑上,一个公司只能有一个老板
*
效率上,尽量少实例化对象避免空间占用
*
其他

1 饿汉模式

最基本的思路,就是将类的构造器私有化,那么就不能在外部调用 new 创建实例了。

其次,通过调用静态方法获取实例。

// 一般情况来说,这种方式就够用了!

public class Boss {    private Boss() {}        private static Boss instance = new Boss();        public static Boss getInstance() {        return instance;        }}

2 懒汉模式以及演进

饿汉模式的问题在于,即使没有用到 boss,它也会被实例化,有些浪费空间…
而懒汉模式就是让 boss 只在用到的时候才去加载。
其设计的思路及代码如下:

public class Boss {    // 1. 私有化构造器    private Boss {}    // 2. 定义实例的变量    private static Boss instance;    // 3. 通过静态方法创建或返回实例    public static Boss getInstance () {        if (instance == null) {            instance = new Boss(); // 虽然构造器是私有的,但是可以在内部调用        }            return instance;    }}

这种方法在单线程下没有任何问题,但是在多线程环境中,却可能会实例化出多个对象。

也就是说,它并不是线程安全的。为了解决这个问题,需要对 getInstance 加锁:

public class Boss {    // 1. 私有化构造器    private Boss {}    // 2. 定义实例的变量    private static Boss instance;    // 3. 通过静态方法创建或返回实例    public synchronized static Boss getInstance () {     // 通过锁,将对此方法的调用变成串行的。这就防止了错误    if (instance == null) {        instance = new Boss(); // 虽然构造器是私有的,但是可以在内部调用    }        return instance;    }}

上述加锁的方式,可以保证正确实例化对象。但是,因为在方法上加了锁,使得获取单例对象的效率过低

这时候,需要兼顾线程安全和效率,就出现了双重检查锁的概念:

// 1. 将构造器私有化private Boss() {}// 2. 初始化一个静态变量private static volatile Boss instance = null;// 3. 构造一个静态方法,通过它初始化或返还对象public static Boss getInstance() {// 双重检查锁机制    if (instance == null) {        synchronized (Boss.class) {        if (instance == null) {            instance = new Boss();        }    }}    return instance;}

其中:

*
synchronized 块尽量缩小了锁定的范围,提高效率
*
volatile 是为防止编译器指令重排而导致双重检查锁失效

另外:

*
指令重排本是为了优化代码执行效率而存在的,虽然在单线程中效果拔群,但是在多线程中却能带来麻烦。volatile 可以要求编译器不要做指令重排。

3 静态内部类方式

这是相对来说,非常优秀的一种实现。在很多地方,推荐使用这种方式。

public class Boss {    // 1. 将构造器私有化    private Boss() { }        // 2. 充分利用了静态内部类的特性,在里面初始化 Boss 实例    // - 只会被初始化一次    // - 只有当静态内部类内部的属性、方法等被调用的时候,静态内部类才会被加载    static class Singleton {        private final static Boss INSTANCE = new Boss();    }    // 3. 提供一个公共方法,获取实例化好之后的对象    public static Boss getInstance() {        return Singleton.INSTANCE;    }}    4 ENUM方式    ENUM 应该是最简单,也是最好的一种实现单例模式的方式。    它充分利用了 JVM 的特性,既保证了线程安全,又保证了延迟加载。        enum Boss {    INSTANCE;        public void sayHello () {            System.out.println("hello");        }    }    public class Main {        public static void main (String... args) {        Boss theBoss = Boss.INSTANCE; // 获取实例        theBoss.sayHello(); // 调用方法        }}

 

 
 
 
 
 
 
 
posted @ 2018-12-07 07:53 阅读(...) 评论(...)

转载地址:http://pthgn.baihongyu.com/

你可能感兴趣的文章
find border vertex
查看>>
matlab sliced variable
查看>>
create symbolic array
查看>>
TAUCS库的编译(vs2010)
查看>>
color vector using in plotting example points and lines between corresponding vertices
查看>>
mex 里面调用matlab函数
查看>>
matlab中cuda编程中分配grid和block dimension的时候的注意事项
查看>>
GPU CUDA and MEX Programming
查看>>
arrayfun用法
查看>>
矩阵积分
查看>>
optimization on macOS
查看>>
Template-Based 3D Model Fitting Using Dual-Domain Relaxation
查看>>
install libfreenect2 on ubuntu 16.04
查看>>
how to use automake to build files
查看>>
using matlab drawing line graph for latex
查看>>
How package finding works
查看>>
build opencv3.3.0 with VTK8.0, CUDA9.0 on ubuntu9.0
查看>>
how to compile kinfu_remake with cuda 9.0 opencv2.4.13.4
查看>>
qtcreator4.4.1中cmake 与cmake3.5.1本身generate出来的setting是有区别的解决方法
查看>>
CMake Useful Variables/Logging Useful Variables
查看>>