java单例模式与线程安全

作者: Tifkingsly | 来源:发表于2018-05-30 01:58 被阅读39次

设计模式在软件架构设计中被经常使用,掌握常用的设计模式对于设计软件系统非常重要。单例模式作为设计模式中最简单和常用的一种模式,java中单例模式具有多种实现方式,以下会对各种实现进行解析。

1、单例模式概念:

顾名思义,单例模式指的是在软件系统运行过程中,某个类只存在一个实例。因此一个类实现单例模式时需要具备以下3个条件:
1)类的内部定义一个该类的静态私有成员变量;
2)构造方法为私有;
3)提供静态工厂方法,供外部获取类的实例;


类图

2、单例模式实现方式:

1)懒汉式单例
public class Singleton {

    private static Singleton instance;

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

懒汉式单例即在使用使用时才创建类的实例,工厂方法增加类synchronized关键字以保证线程安全。在多线程访问的环境下,同步方法导致系统性能下降。优点在于,类加载时不用自行实例化对象,避免加载缓慢。

2)饿汉式单例
public class Singleton {

    private static Singleton instance = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

饿汉式单例,在类加载式自行实例化对象。优点在于多线程环境下不会出现线程安全问题,因为类只加载一次。缺点在于,系统加载时消耗额外资源,如果该实例没有使用的情况会造成资源浪费。

3)双重检测单例
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;
    }
}

双重检测锁定(Double-Check Locking)方案属于懒汉式,使用延时加载技术,避免类加载时任务过重和造成资源浪费,同时将synchronized关键字加在代码块中,减少线程同步锁定以提升系统性能。instance实例使用了volatile关键字修饰,主要是避免在多线程环境下由于编译器进行的重排序操作而导致的线程安全问题。JVM在创建一个对象时会进行以下步骤:
1)分配对象内存空间;
2)初始化对象;
3)设置instance指向分配的内存地址;
编译器为了优化性能,可能会将2、3操作调换顺序,假设A线程在执行new Singleton()方法时,由于2、3操作重排序,而初始化对象操作尚未完成时释放了锁。线程B获取锁之后会发现instance已经不为空,当线程B获取到instance对象后如果直接使用就会出错,原因就是对象没有进行初始化操作。而volatile关键字能避免重排序,因此能保证线程安全。总体上来说,双重检测由于加了锁,多线程并发下还是会有效率问题。

4)枚举单例
public enum  Singleton {
    INSTANCE
}

枚举单例模式,不会存在线程安全问题,不过在Android平台下,枚举类性能相对较低。

5)静态内部类单例
public class   Singleton {


    private Singleton() {

    }

    public static Singleton getInstance() {
        return SingletonFactory.instance;
    }

    static class SingletonFactory {
        private final static Singleton instance = new Singleton();
    }
}

静态内部类单例模式是一种比较优秀的实现方式,也是《Effective Java》书中推荐的方式。一方面,使用延时加载,使用时才进行对象初始化,也不会造成造成资源浪费;另一方面,由于JVM在类的加载时已经做了同步处理,不会出现线程安全问题。

结束语

文中介绍单例模式的一些基础知识点,以及多种实现方式的优缺点分析。在日常开发中,推荐使用静态内部类实现单例模式。相对其他设计模式而言,单例模式是非常简单的。

相关文章

  • Java 单例模式

    概述 Java中单例模式是一种常见的设计模式,单例模式总共有7种写法。 懒汉,线程不安全 懒汉,线程安全 饿汉 饿...

  • Kotlin 的单例模式

    Kotlin 的单例模式 1. 在 Java 中的单例模式 懒汉式单例模式,并且是线程安全 2. 在 Kotlin...

  • 单例模式的常用实现方式

    单例模式属于最常用的设计模式,Java中有很多实现单例模式的方式,各有其优缺点 实现方式对比 单例实现方式线程安全...

  • 单例模式汇总

    Java单例模式 java单例模式是为了让全局只实例化一个对象,常用的方式包括懒汉模式、饿汉模式,考虑到线程安全,...

  • 单例

    单例,是Java中很重要的一个设计模式。 实现单例是要考虑并发(线程安全)问题的。 如何实现一个线程安全的单例?你...

  • 深入理解 Java 内存模型

    一、概述 在之前 单例模式的Java实现与思考 一文里讲到,为了使用 DCL 实现线程安全的单例模式,需要对实例变...

  • Java多线程--并行模式与算法

    Java多线程--并行模式与算法 单例模式 虽然单例模式和并行没有直接关系,但是我们经常会在多线程中使用到单例。单...

  • kotlin实现单例

    java实现单例模式 一直习惯于java的写法,java实现单例主要的思想是构造函数私有,然后考虑线程安全,在实现...

  • 设计模式

    手写单例模式(线程安全) 你知道几种设计模式?单例模式是什么?Spring中怎么实现单例模式?

  • Kotlin设计模式-单例模式

    单例模式是项目中最常见的工具类使用模式 kotlin中单例的最佳实践方式,线程安全的懒汉模式 java中调用 ko...

网友评论

    本文标题:java单例模式与线程安全

    本文链接:https://www.haomeiwen.com/subject/fxizjftx.html