原文地址设计模式:单例模式
单例模式保证一个类仅有一个实例,并提供一个访问他的全局函数。当系统开发中某个类只能有一个实例时,就可以采用单例模式。
单例模式
单例模式是一种常用的软件设计模式。在他的核心 结构中只包含一个被称为单例的特殊类,保证系统中该类只有一个实例。
总之,单例模式具有以下特点:
- 单例类只能有一个实例
- 单例类必须自己创建自己唯一的实例
- 单例类必须给所有的其他对象都能提供这一实例。
保证单例模式仅有一个实例的核心思想是构造方法私有化,所以单例模式的方法主要有以下两种。
直接实例化
/**
* @author William Mou
* @date 2019/4/27 18:53
* 直接生成实例
*/
public class Singleton1 {
private static final Singleton1 SINGLETON_1 = new Singleton1();
//避免外部调用
private Singleton1() {
System.out.println("初始化单例模式");
}
//返回单例对象的实例
public static Singleton1 getInstance() {
return SINGLETON_1;
}
}
延迟实例化
/**
* @author William Mou
* @date 2019/4/27 18:58
* 延迟实例化
*/
public class Singleton2 {
private static volatile Singleton2 singleton2 = null;
private Singleton2() {
System.out.println("初始化实例");
}
// 方法一:单线程
public static Singleton2 getInstance1() {
if (singleton2 == null) {
singleton2 = new Singleton2();
}
return singleton2;
}
}
与直接实例化不同,单例成员变量singleton2首先初始化为null,它在方法getInstance()内完成延迟实例化,并返回单例对象,但是该方法存在线程安全问题。如果两个线程都在执行getInstance()方法,线程一已经在执行if (singleton2 == null)
后,在执行完singleton2 = new Singleton2()
前,线程二正在执行if (singleton2 == null)
也成立,这样将会生成两个单例对象,违背了单例模式。
线程安全-synchronized完全同步方法
public static synchronized Singleton2 getInstance2() {
if (singleton2 == null) {
singleton2 = new Singleton2();
}
return singleton2;
}
使用synchronized关键字后,当多线程同时访问getInstance()方法的时候,多线程将穿行运行。
线程安全-synchronized部分同步方法
// 方法三:多线程synchronized代码块
public static Singleton2 getInstance3() {
if (singleton2 == null) {
synchronized (Singleton2.class){
if (singleton2 == null){ //再次确认对象是否实例化
singleton2 = new Singleton2();
}
}
}
return singleton2;
}
此方法中,只有当对象还没实例化的时候会串行执行,其他的时候可并行运行。与完全同步方法相比,提高了运行效率。
线程安全-静态内部类
/**
* @author William Mou
* @date 2019/4/27 19:08
* 静态内部类
*/
public class Singleton3 {
private Singleton3(){
System.out.println("实例初始化");
}
private static class My{
private static final Singleton3 SINGLETON_3 = new Singleton3();
}
public static Singleton3 getInstance(){
return My.SINGLETON_3;
}
}
与使用synchronized关键字的方法相比,此方法提高了Java虚拟机的维护效率,而且此方法还是线程安全的。