定义:保证一个类有且仅有一个实例,并且自行实例化(无需手动new)向整个系统提供。
通过单例模式可以保证系统内只会存在该类的一个实例,从而方便了对实例数量的控制和系统资源的节约。如果希望在系统中,某个类的实例只存在一个,那单例模式是最好的解决方案。所谓一山不能容二虎,一夫不能有二妻,就是这个道理。
单例模式要素:
1.私有构造方法
2.私有静态引用指向自己实例
3.以自己实例为返回值的公有静态方法
使用场景:
1.要求生成唯一序列号的环境
2.在整个项目中需要一个共享访问点或共享数据,例如一个Web页面上的计数器,可以不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的
3.创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源
4.需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当然,也可以直接声明为static的方式)
5.配合配置信息进行使用,例如将配置信息放入一个properties文件中,利用一个单例可以获取该文件中的各项配置内容
单例模式又称为单子模式或singleton模式。singleton模式又分为两种:懒汉式和饿汉式。
懒汉式
/**
* 单例模式-懒汉式
*
* @auth zhangjingxuan
* @since 2018年4月11日上午9:47:50
*/
public class Singleton2 {
//1.创建类的唯一实例,使用private static修饰
private static Singleton2 instance;
//2.将构造方式私有化,不允许外边直接创建对象
private Singleton2() {
System.out.println("Singleton2初始化完毕");
}
//3.提供一个用于获取实例的方法,使用public static修饰
public static Singleton2 getInstance(){
if(instance==null){
instance=new Singleton2();
}
return instance;
}
//4.其他方法尽可能使用static进行修饰
public static void doSomething() {
System.out.println("Singleton2 doSomething");
}
}
饿汉式
/**
* 单例模式-饿汉式
*
* @auth zhangjingxuan
* @since 2018年4月11日上午9:45:30
*/
public class Singleton1 {
//1.创建类的唯一实例,使用private static修饰
private static Singleton1 instance = new Singleton1();
//2.将构造方式私有化,不允许外边直接创建对象
private Singleton1() {
System.out.println("Singleton1初始化完毕");
}
//3.提供一个用于获取实例的方法,使用public static修饰
public static Singleton1 getInstance(){
return instance;
}
//4.其他方法尽可能使用static进行修饰
public static void doSomething() {
System.out.println("Singleton1 doSomething");
}
}
测试
public class Test {
public static void main(String[] args) {
Singleton1.doSomething();
Singleton2.doSomething();
}
}
结果
Singleton1初始化完毕
Singleton1 doSomething
Singleton2 doSomething
懒汉式vs饿汉式:
1.在编码上主要区别是上述代码的第一步,是否需要在getInstance()之前进行实例化
2.懒汉式的特点是加载类的时候比较快,但运行时获取实例时比较慢,线程不安全
3.饿汉式的特点是加载类的时候比较慢(需要实例化),但运行时获取实例(getInstance())时比较快,线程安全
4.当懒汉式不获取实例而直接调用doSomething时,不会实例化操作
5.当饿汉式不获取实例而直接调用doSomething时,依然进行实例化操作
综上可知,懒汉模式是线程安全的,但在某些场景下会浪费系统资源。饿汉模式是线程不安全的,但相对懒汉模式会节约系统资源。所以,如果能有一种包含单例特点、线程安全和节约系统资源三种特点为一身的写法该有多好!程序界有一句话是“只要你能想到,我们就能给你做到”,因此这种奢华的写法也出现了。
线程安全&节约资源的单例模式(懒汉式+线程锁)
/**
* 单例模式-懒汉式
*
* @auth zhangjingxuan
* @since 2018年4月11日上午9:47:50
*/
public class Singleton3 {
//1.防止利用反射调用单例,从而破坏单例模式的flag(在构造函数中会用到)
private static boolean initialized = false;
//2.静态的内部类(寄生虫),解决多线程安全问题
private static class LazyHolder {
private static final Singleton3 instance = new Singleton3();
}
//3.构造函数(配合initialized使用)
private Singleton3() {
//解决反射破坏到单例
synchronized (Singleton3.class) {
if (!initialized) {
initialized = true;
System.out.println("Singleton3初始化完毕");
} else {
throw new RuntimeException("禁止初始化...");
}
}
}
//4.提供一个用于获取实例的方法,使用public static修饰
public static Singleton3 getInstance() {
return LazyHolder.instance;
}
public static void doSomething() {
System.out.println("Singleton3 doSomething");
}
}
感谢以下博客达人,摘要文献来自以下: