简介
单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。即一个类只有一个对象实例。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序等对象常被设计成单例。
UML图
模式分析
单例模式的目的是保证一个类仅有一个实例,并提供一个访问它的全局访问点。单例模式包含的角色只有一个,就是单例类——Singleton。单例类拥有一个私有构造函数,确保用户无法通过new关键字直接实例化它。除此之外,该模式中包含一个静态私有成员变量与静态公有的工厂方法,该工厂方法负责检验实例的存在性并实例化自己,然后存储在静态成员变量中,以确保只有一个实例被创建。在单例模式的实现过程中,需要注意如下三点:
单例类的构造函数为私有;
提供一个自身的静态私有成员变量;
提供一个公有的静态工厂方法。
懒汉式
线程不安全
//懒汉式单例,在第一次调用时实例化自己(线程不安全)
/**
* 只能在单线程下使用。如果在多线程下,一个线程进入了if (singleton == null)判断语句块,还未来得及往
* 下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式。
**/
public class Singleton {
private static Singleton singleton;
// 私有化构造
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
线程安全
// 线程安全
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
// 线程安全。双重检查锁。
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
singleton = new Singleton();
}
}
return singleton;
}
}
// 静态内部类实现方式
public class Singleton {
private Singleton() {}
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
三种线程安全懒汉式比较:
- 第一种在方法调用上增加了同步,线程安全,但每次都需要同步。这样会对性能有影响。毕竟大部分情况是不需要同步的。
- 第二种在方法上做了两次实例是否为null的检查,确保了只有第一调用的时候同步。这样能避免每次同步的性能消耗。
- 第三种利用了ClassLoader的机制来办证初始化instance只有一个线程。所以也是线程安全并且没有性能损耗问题。
补充,
// 双重检查,两次if判断 public class Singleton { private static volatile Singleton singleton; private Singleton() {} public static Singleton getInstance() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
进行了两次if (singleton == null)检查,这样就可以保证线程安全了。这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象。
饿汉式
// 饿汉式,静态常量方式
public class Singleton {
private final static Singleton INSTANCE = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
}
// 饿汉式 静态代码块
public class Singleton {
private static Singleton instance;
static {
instance = new Singleton();
}
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
两种方式比较
- 两种方式的区别在于一个是定义的静态变量,另一个是静态代码块中。两者的优缺点一致:
- 优点是写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。
- 缺点是在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费
第一篇简陋的博客、(*^▽^*)