一、基本介绍
单例模式(创建型):采用一定的方式保证在整个软件系统中,对某个类只存在一个对象实例,并提供一个取得该实例对象的方法(静态方法)。
二、包含角色
1.单例类:包含一个实例且能自行创建这个实例的类,并提供获取这个实例的方法。
2.访问类:使用单例类的类。
三、案例及UML类图
UML类图:
方式一:懒汉模式(静态常量)
代码:
public class Singleton1 {
/**
* 1. 构造器私有化
*/
private Singleton1() {
}
/**
* 2.类内部创建实例对象(通过静态常量)
*/
private final static Singleton1 singleton = new Singleton1();
/**
* 3.通过提供静态方法让外部获取
*/
public static Singleton1 getSingleton() {
return singleton;
}
}
此模式的优缺点:
优:该方式在类加载时就会实例化,不用担心同步的问题。
缺:如果未使用到该实例,则会浪费内存。
方式二:饿汉模式(静态代码块)
public class Singleton2 {
/**
* 1. 构造器私有化
*/
private Singleton2() {
}
private final static Singleton2 singleton;
/**
* 2.类内部创建实例对象(通过静态代码块)
*/
static {
singleton = new Singleton2();
}
/**
* 3.通过提供静态方法让外部获取
*/
public static Singleton2 getSingleton() {
return singleton;
}
}
此模式的优缺点:
优:该方式在类加载时就会实例化,不用担心同步的问题。
缺:如果未使用到该实例,则会浪费内存。
方式三:懒汉模式
public class Singleton3 {
/**
* 1. 构造器私有化
*/
private Singleton3() {
}
private static Singleton3 singleton;
/**
* 2.通过提供静态方法让外部获取
*/
public static Singleton3 getSingleton() {
//3.当首次获取时才创建
if(singleton == null) {
singleton = new Singleton3();
}
return singleton;
}
}
此模式的优缺点:
优:使用了懒加载的模式,避免内存浪费。
缺:只能单线程中使用,多线程下会有同步问题。
方式四:懒汉模式(同步锁)
public class Singleton4 {
/**
* 1. 构造器私有化
*/
private Singleton4() {
}
private static Singleton4 singleton;
/**
* 2.通过提供静态方法让外部获取,方法加锁
*/
public static synchronized Singleton4 getSingleton() {
//3.当首次获取时才创建
if(singleton == null) {
singleton = new Singleton4();
}
return singleton;
}
}
此模式的优缺点:
优:使用了懒加载的模式,避免内存浪费。
缺:解决了同步问题,但锁的粒度较大。
方式五:双重检查
public class Singleton5 {
/**
* 1. 构造器私有化
*/
private Singleton5() {
}
//volatile 防止指令重排序,即当singleton在创建过程中(未创建完成,但有了地址)而第二个获取来到了第一次检查时,直接return从而导致指令重排序。
private static volatile Singleton5 singleton;
/**
* 2.通过提供静态方法让外部获取,方法加锁
*/
public static Singleton5 getSingleton() {
//3.当首次获取时才创建
if(singleton == null) {
//加锁 双重检查
synchronized (Singleton5.class) {
if(singleton == null) {
singleton = new Singleton5();
}
}
}
return singleton;
}
}
推荐使用此方式。
第六种:静态内部类
public class Singleton6 {
/**
* 1. 构造器私有化
*/
private Singleton6() {
}
/**
* 2.静态内部类私有化
*/
private static class SingletonHoler {
private static Singleton6 singleton = new Singleton6();
}
/**
* 3.通过提供静态方法让外部获取,方法加锁
*/
public static Singleton6 getSingleton() {
return SingletonHoler.singleton;
}
}
推荐使用此方式。
说明:类在实例化时,虚拟机会帮我们处理同步问题,
四、适用场景
1.需要频繁的创建和销毁对象时
2.创建重量级的对象
3.经常使用到的对象