Java实现单例模式(懒汉式、饿汉式、双重检验锁、静态内部类方式、枚举方式)

原创 2018年04月17日 11:28:59

目录


懒汉式单例

懒汉式单例模式在第一次调用的时候进行实例化。

/**
 * Title:Singleton1<br>
 * Description:单例模式——懒汉式
 * 
 * @author QiuChangjin
 * @date 2018年4月17日
 */
public class Singleton1 {

    private static Singleton1 instance = null;

    private Singleton1() {
    }

    /**
     * 1、适用于单线程环境(不推荐)
     */
    public static Singleton1 getInstanceA() {
        if (null == instance) {
            instance = new Singleton1();
        }
        return instance;
    }

    /**
     * 2、适用于多线程环境,但效率不高(不推荐)
     */
    public static synchronized Singleton1 getInstanceB() {
        if (instance == null) {
            instance = new Singleton1();
        }
        return instance;
    }

    /**
     * 3、双重检查加锁(推荐)
     */
    public static Singleton1 getInstanceC() {
        // 先判断实例是否存在,若不存在再对类对象进行加锁处理
        if (instance == null) {
            synchronized (Singleton1.class) {
                if (instance == null) {
                    instance = new Singleton1();
                }
            }
        }
        return instance;
    }
}

1、适用于单线程环境(不推荐)

此方式在单线程的时候工作正常,但在多线程的情况下就有问题了。如果两个线程同时运行到判断instance是否为null的if语句,并且instance的确没有被创建时,那么两个线程都会创建一个实例,此时类型Singleton1就不再满足单例模式的要求了。

    public static Singleton1 getInstanceA() {
        if (null == instance) {
            instance = new Singleton1();
        }
        return instance;
    }
}

2、适用于多线程环境,但效率不高(不推荐)

为了保证在多线程环境下我们还是只能得到该类的一个实例,只需要在getInstanceB()方法加上同步关键字sychronized,就可以了。每次调用getInstanceB()方法时都被synchronized关键字锁住了,会引起线程阻塞,影响程序的性能。

public static synchronized Singleton1 getInstanceB() {
        if (instance == null) {
            instance = new Singleton1();
        }
        return instance;
    }

3、双重检验锁

为了在多线程环境下,不影响程序的性能,不让线程每次调用getInstanceC()方法时都加锁,而只是在实例未被创建时再加锁,在加锁处理里面还需要判断一次实例是否已存在。

    public static Singleton1 getInstanceC() {
        // 先判断实例是否存在,若不存在再对类对象进行加锁处理
        if (instance == null) {
            synchronized (Singleton1.class) {
                if (instance == null) {
                    instance = new Singleton1();
                }
            }
        }
        return instance;
    }

4、静态内部类方式(推荐

加载一个类时,其内部类不会同时被加载。一个类被加载,当且仅当其某个静态成员(静态域、构造器、静态方法等)被调用时发生。 由于在调用 StaticSingleton.getInstance() 的时候,才会对单例进行初始化,而且通过反射,是不能从外部类获取内部类的属性的;由于静态内部类的特性,只有在其被第一次引用的时候才会被加载,所以可以保证其线程安全性。
总结:
优势:兼顾了懒汉模式的内存优化(使用时才初始化)以及饿汉模式的安全性(不会被反射入侵)。
劣势:需要两个类去做到这一点,虽然不会创建静态内部类的对象,但是其 Class 对象还是会被创建,而且是属于永久带的对象。

/**
 * Title:StaticSingleton<br>
 * Description:单例模式——静态内部类方式
 * 
 * @author QiuChangjin
 * @date 2018年4月17日
 */
public class StaticSingleton {
    /**
     * 私有构造方法,禁止在其他类中创建实例
     */
    private StaticSingleton() {
    }

    /**
     * 获取实例
     */
    public static StaticSingleton getInstance() {
        return StaticSingletonHolder.instance;
    }

    /**
     * 一个私有的静态内部类,用于初始化一个静态final实例
     */
    private static class StaticSingletonHolder {
        private static final StaticSingleton instance = new StaticSingleton();
    }

    /**
     * 方法A
     */
    public void methodA() {
    }

    /**
     * 方法B
     */
    public void methodB() {
    }

    public static void main(String[] args) {
        StaticSingleton.getInstance().methodA();
        StaticSingleton.getInstance().methodB();
    }
}

饿汉式单例

1、饿汉式(推荐)

饿汉式单例类:在类初始化时,已经自行实例化。

/**
 * Title:Singleton2<br>
 * Description:单例模式——饿汉式
 * 
 * @author QiuChangjin
 * @date 2018年4月17日
 */
public class Singleton2 {

    private static final Singleton2 instance = new Singleton2();

    private Singleton2() {
    }

    public static Singleton2 getInstance() {
        return instance;
    }
}

2、枚举方式(推荐)

创建枚举默认就是线程安全的,所以不需要担心double checked locking,而且还能防止反序列化导致重新创建新的对象。保证只有一个实例(即使使用反射机制也无法多次实例化一个枚举量)。

/**
 * Title:Singleton<br>
 * Description:单例模式——枚举方式
 * 
 * @author QiuChangjin
 * @date 2018年4月17日
 */
public class Singleton {
    public static void main(String[] args) {
        Single single = Single.SINGLE;
        single.print();
    }

    enum Single {
        SINGLE;

        private Single() {
        }

        public void print() {
            System.out.println("hello world");
        }
    }
}

总结

就我个人而言,一般情况下直接使用饿汉式就好了,如果明确要求要懒加载(lazy initialization)会倾向于使用静态内部类,如果涉及到反序列化创建对象时会试着使用枚举方式来实现单例。

单例模式有五种写法:懒汉、饿汉、双重检验锁、静态内部类、枚举。

转 https://biezhi.me/article/how-to-correctly-write-singleton-pattern.html 单例模式算是设计模式中最容易理解,也是最容易手...
  • nsw911439370
  • nsw911439370
  • 2016-01-04 15:22:07
  • 7850

1.单例设计模式(懒汉式,饿汉式,枚举式,双重检测锁式,静态内部类式)

设计模式分类: 1:创建型模式: 单例模式,工厂模式,抽象工厂模式,建造者模式,原型模式; 2:结构型模式: 适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式 3:行为型模式: ...
  • u012572955
  • u012572955
  • 2015-08-11 22:27:05
  • 2989

黑马程序员一单例设计模式的饿汉式与懒汉式以及加锁的情况

首先,我们以类Single为例,做一个单例设计模式 一个类在内存中只有一个对象,只操作一个对象,所以该类只会提供一个获得对象的方法, 返回值类型为类类型,返回的内容为对象 //同步函数被静态...
  • li495512592
  • li495512592
  • 2014-12-01 08:22:05
  • 1101

单例模式三种实现----饿汉式 饱汉式(懒汉式) 双重锁模式--------(java复习)

在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。 一、什么时候使用单例模式: 当实例存...
  • qq_27093465
  • qq_27093465
  • 2016-03-25 13:56:01
  • 4778

单例模式(懒汉式、双重锁、饿汉式、登记式)

单例模式确保某一个类只有一个实例 1.懒汉式是延时加载,在需要的时候才创建对象,避免内存浪费。但面临着多线程访问的安全性问题,需要做双重锁定才能保证安全。双重锁模式将同步内容下放到if内...
  • liyue199512
  • liyue199512
  • 2016-08-06 13:02:08
  • 678

单例模式---懒汉与饿汉模式和静态内部类实现

单例模式是最基本的 java 设计模式之一 主要有两种设计方法,主要分为饿汉式与懒汉式饿汉式比较简单,直接使用常量即可,主要代码如下: private static final SingleM...
  • jslcylcy
  • jslcylcy
  • 2017-05-25 11:44:26
  • 639

比饿汉单例模式和懒汉单例模式更好的静态内部类单例模式

简介单例模式是一种常见的模式,懒汉模式考虑线程安全需要在获取单例的方法添加synchronized关键字实现同步代码块,这样造成了性能损耗;而饿汉模式不能延迟实例化对象,下面是一个静态内部类单例模式的...
  • u014788453
  • u014788453
  • 2016-08-16 16:54:58
  • 1176

Java实现单例模式之饿汉式、懒汉式、枚举式,带测试。

Java实现单例的3种普遍的模式,饿汉式、懒汉式、枚举式。
  • qq_29542611
  • qq_29542611
  • 2016-10-23 23:54:19
  • 3872

多种单例模式

  • 2017年11月30日 19:05
  • 3KB
  • 下载

Java单例模式--饿汉式、懒汉式需要怎么写

Java 单例模式 饿汉 懒汉 spring IOC中使用懒汉式、饿汉式
  • u013905744
  • u013905744
  • 2016-10-07 14:23:31
  • 3971
收藏助手
不良信息举报
您举报文章:Java实现单例模式(懒汉式、饿汉式、双重检验锁、静态内部类方式、枚举方式)
举报原因:
原因补充:

(最多只允许输入30个字)