java设计模式-单例模式

Posted 醉东风

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java设计模式-单例模式相关的知识,希望对你有一定的参考价值。

单例模式

定义

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建型模式。

 

实现步骤

(1)     定义静态私有成员变量

(2)     创建唯一实例(多种实现方式)

(3)     定义私有构造函数,确保外部不能使用new关键字创建对象

(4)     提供外部获取单例对象的静态方法

 

实现方式

饿汉式单例类

饿汉式单例类是最简单的单例类,定义的静态私有成员变量在类加载的时候就会创建单例对象。饿汉式单例是线程安全的,不会出现创建多个单例对象的情况。

代码实现
/**
 * 饿汉式单例类
 * @create 2018-04-12 17:05
 **/
public class EagerSingleton {

    //定义静态私有成员变量,创建单例对象
    private static EagerSingleton instance = new EagerSingleton();

    //定义私有构造函数,确保外部不能使用new关键字创建EagerSingleton实例对象
    private EagerSingleton() {

    }

    //提供外部获取单例对象的静态方法
    public static EagerSingleton getInstance() {
        return instance;
    }
}

 

优缺点

优点:线程安全,在多线程下不会出现创建多个实例对象的情况。

缺点:未实现懒加载,类加载时即初始化单例对象,加载时间可能较长。

 

懒汉式单例类

懒汉式单例也是一种实现单例的经典方式,单例对象不是在类加载时创建,而是在第一次调用getInstance方法时创建,实现了懒加载,但是在多线程下会出现创建多个单例对象的情况。

非线程安全代码实现
/**
 * 非线程安全懒汉式单例类
 * @create 2018-04-12 22:14
 **/
public class LazySingleton {
    //定义静态私有成员变量
    private static LazySingleton instance = null;

    //定义私有构造函数,确保外部不能使用new关键字创建EagerSingleton实例对象
    private LazySingleton() {

    }

    //提供外部获取单例对象的静态方法
    public static LazySingleton getInstance() {
        if (null == instance) {
            //创建单例对象
            instance = new LazySingleton();
        }
        return instance;
    }
}

 

优缺点

优点:实现懒加载

缺点:非线程安全,在多线程下不能正常工作

 

线程安全代码实现
/**
 * 线程安全懒汉式单例类
 * @create 2018-04-12 22:14
 **/
public class LazySingleton {
    //定义静态私有成员变量
    private static LazySingleton instance = null;

    //定义私有构造函数,确保外部不能使用new关键字创建EagerSingleton实例对象
    private LazySingleton() {

    }

    //创建实例对象时,加上线程锁,实现线程安全
    public static synchronized LazySingleton getInstance() {
        if (null == instance) {
            //创建单例对象
            instance = new LazySingleton();
        }
        return instance;
    }
}

 

优缺点

优点:实现懒加载、线程安全。

缺点:由于给getInstance方法加了线程锁,每次调用该方法时,都会被锁住,在多线程环境下,运行效率很低。

 

可以给上面这种方式进行优化,线程锁加载创建单例对象的地方,而不直接加在getInstance方法上。

优化后的代码:

package com.lnjecit.singleton;

/**
 * 线程安全懒汉式单例类
 *
 * @create 2018-04-12 22:14
 **/
public class LazySingleton {
    //定义静态私有成员变量
    private static LazySingleton instance = null;

    //定义私有构造函数,确保外部不能使用new关键字创建EagerSingleton实例对象
    private LazySingleton() {

    }

    //创建实例对象时,加上线程锁,实现线程安全
    public static LazySingleton getInstance() {
        if (null == instance) {
            synchronized (LazySingleton.class) {
                //创建单例对象
                instance = new LazySingleton();
            }
        }
        return instance;
    }
}

 

这种方式可以在一点程度上提高运行效率,但是还是在多线程情况下,还是有可能出现创建多个单例,当instance为null时,多个线程同时访问getInstance方法,由于instance为null,所以都会创建instance对象,

造成出现多个实例。

 

双重锁定
代码实现
/**
 * 双重校验锁定单例类
 * @create 2018-04-12 22:14
 **/
public class LazySingleton {
    /**
     *定义静态私有成员变量,
     *使用volatile关键字修饰,确保线程可见性,当一个线程修改了instance对象,其它线程也能看到修改后的值
     */
    private volatile static LazySingleton instance = null;

    //定义私有构造函数,确保外部不能使用new关键字创建EagerSingleton实例对象
    private LazySingleton() {

    }

    //创建实例对象时,加上线程锁,实现线程安全
    public static LazySingleton getInstance() {
        if (null == instance) {
            synchronized (LazySingleton.class) {
                if (null == instance) {
                    //创建单例对象
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }
}

 

优缺点

优点:实现懒加载、线程安全。

缺点:volitile关键字会屏蔽JVM对代码的优化,存在导致运行效率低的可能。 

 

内部静态类

饿汉式单例类不能实现懒加载,懒汉式需要加锁、判断等方式确保线程安全,实现过程繁琐。而在单例内中增加一个内部静态类可减少加锁和判断的过程,就可实现懒加载和线程安全,并且不影响运行效率。

实现代码
/**
 * 静态内部类
 * @create 2018-04-12 17:05
 **/
public class Singleton {

    //定义私有构造函数,确保外部不能使用new关键字创建EagerSingleton实例对象
    private Singleton() {

    }

    private static class SingletonHolder {
        //创建单例对象
        private static final Singleton INSTANCE = new Singleton();
    }

    //提供外部获取单例对象的静态方法
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

 

优缺点

 优点:懒加载、线程安全。

 缺点: 

应用场景

请参考:

https://blog.csdn.net/lovelion/article/details/7420889

https://blog.csdn.net/tanyujing/article/details/14160941

 

参考资料

1、https://blog.csdn.net/lovelion/article/details/7420886

以上是关于java设计模式-单例模式的主要内容,如果未能解决你的问题,请参考以下文章

java 单例模式这个要怎么理解?

Java设计模式--单例模式(代码详解懒汉饿汉模式)

Java中的单例模式

Java设计模式之单例模式

Java 设计模式——单例模式 理论代码相结合

Java模式设计之单例模式(二)