1、模式的定义和特点
单例(Singleton)模式:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。它是最简单的设计模式之一。
特点:
1、单例类只能有一个实例
2、单例类必须自己创建自己的唯一实例
3、单例类对外提供一个访问该单例的全局访问点
缺点:
没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
单例模式有多种写法,大部分都有以下关键代码(枚举写法除外):
1、私有的类类型变量
2、私有的构造方法
3、公共的获取实例的方法
2、模式的结构
主要角色:
单例类:包含一个实例且能自行创建这个实例的类。
访问类:使用单例的类。
3、模式的使用场景
1、某类只要求生成一个对象的时候,如一个班中的班长、每个人的身份证号等。
2、当对象需要被共享的场合。
由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如 Web 中的配置对象、数据库的连接池等。
3、当某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。
4、单例模式的扩展
单例模式可扩展为有限的多例(Multitcm)模式,这种模式可生成有限个实例并保存在 ArrayList 中,客户需要时可随机获取,其结构图如图1-2所示。
5、模式的实现
5.1 懒汉式-线程不安全
单例类Singleton.java:
package com.example.designpattern.singleton;
class Singleton {
/**
* 1、懒汉式,线程不安全,不支持多线程,懒加载
*/
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
访问类Client.java:
package com.example.designpattern.singleton;
/**
* @author Administrator
* @date 2020/7/23
* <p>
* 经验之谈:
* 1、一般情况下,不建议使用第1种和第2种懒汉方式,建议使用第3种饿汉方式。
* 2、只有在要明确实现lazy loading效果时,才会使用第5种登记方式。
* 3、如果涉及到反序列化创建对象时,可以尝试使用第6种枚举方式。
* 4、如果有其他特殊的需求,可以考虑使用第4种双检锁方式。
*/
class Client {
public static void main(String[] args) {
//1、懒汉式
Singleton s1 = Singleton.getInstance();
Singleton s11 = Singleton.getInstance();
System.out.println(s1 == s11);
//2、懒汉式,线程安全
Singleton2 s2 = Singleton2.getInstance();
Singleton2 s22 = Singleton2.getInstance();
System.out.println(s2 == s22);
//3、饿汉式
Singleton3 s3 = Singleton3.getInstance();
Singleton3 s33 = Singleton3.getInstance();
System.out.println(s3 == s33);
//4、双检索
Singleton4 s4 = Singleton4.getInstance();
Singleton4 s44 = Singleton4.getInstance();
System.out.println(s4 == s44);
//5、静态内部类
Singleton5 s5 = Singleton5.getInstance();
Singleton5 s55 = Singleton5.getInstance();
System.out.println(s5 == s55);
//6、枚举
EnumSingleton e = EnumSingleton.INSTANCE;
EnumSingleton ee = EnumSingleton.getInstance();
System.out.println(e == ee);
}
}
判断生成的实例是否一样,测试结果:
另外几种单例模式写法详见下列代码
5.2 懒汉式-线程安全
package com.example.designpattern.singleton;
class Singleton2 {
/**
* 2、懒汉式,线程安全,支持多线程,懒加载
* 与方法1相比,使用了synchronized
*/
private static Singleton2 instance;
private Singleton2 (){}
public static synchronized Singleton2 getInstance() {
if (instance == null) {
instance = new Singleton2();
}
return instance;
}
}
5.3 饿汉式
package com.example.designpattern.singleton;
class Singleton3 {
/**
* 3、饿汉式,多线程安全,非懒加载
*/
private static Singleton3 instance = new Singleton3();
private Singleton3() {
}
public static Singleton3 getInstance() {
return instance;
}
}
5.4 双检锁
package com.example.designpattern.singleton;
class Singleton4 {
/**
* 4、双检锁/双重校验锁(DCL,即 double-checked locking)
* 多线程安全,懒加载
*/
private volatile static Singleton4 singleton;
private Singleton4() {
}
public static Singleton4 getInstance() {
if (singleton == null) {
synchronized (Singleton4.class) {
if (singleton == null) {
singleton = new Singleton4();
}
}
}
return singleton;
}
}
5.5 静态内部类
package com.example.designpattern.singleton;
class Singleton5 {
/**
* 5、登记式/静态内部类
* 多线程安全,懒加载
*/
private static class Inner {
private static final Singleton5 INSTANCE = new Singleton5();
}
private Singleton5() {
}
public static Singleton5 getInstance() {
return Inner.INSTANCE;
}
}
5.6 枚举
package com.example.designpattern.singleton;
/**
* 6、枚举
* JDK1.5起,多线程安全,非懒加载
* 实现单例模式的最佳方法
*/
enum EnumSingleton {
/**
* 枚举值
*/
INSTANCE;
//doSomething 该实例支持的行为
/**
* 可以省略此方法,通过EnumSingleton.INSTANCE进行操作
*/
public static EnumSingleton getInstance() {
return EnumSingleton.INSTANCE;
}
}
6、PPT素材
微信公众号: TechU