类的计划生育(单例模式)
- 概念
- 类图
- 代码实例
概念
允许类产生仅且只有一个对象,如何在多线程环境下实现这一功能应该是这个类来控制的,所以需要实现产生单个实例关键点有以下几点
1、构造器设置为private
2、有一个包含本来的字段,并且是static类型,如果采用double check方式还需要增加volatile修饰保证可见性和有序性
3、创建对象的时机(类一加载时就创建这个实例是饥饿式 在使用该对象的时候创建这个实例为饱汉式)
4、提供一个全局获取实例方法,由于不能在外部new那么该方法为static类型
5、在多线程环境下依然要保证只能有且仅有一个实例
类图
SingletonObject:单例对象类,类的内部进行控制如何实现仅仅返回一个实例逻辑
Client:客户端测试
代码实例
SingletonDoubleCheck 使用双重判断+synchronized+volatile保证多线程下依然获取到单个实例对象
/**
* 为了能在多线程环境下也能保证线程安全,使用double-check双重检测
*/
public class SingletonDoubleCheck {
//volatile 保证可见性,有序性
private volatile static SingletonDoubleCheck singletonDoubleCheck;
//避免外部通过new来创建对象
private SingletonDoubleCheck() {
}
public static SingletonDoubleCheck getInstance() {
//此处判断避免了每次都需要加上锁,提高了获取对象性能
if (singletonDoubleCheck == null) {
synchronized (SingletonDoubleCheck.class) {
if (singletonDoubleCheck
== null) {//如果不使用double check,会导致多线程并发获取实例时,多次创建对象,使用 volidate也避免了指令重排和可见性(如果不用volidate修饰//new 对象会经历三个过程 1、开辟内存空间 2、初始化对象值 3、将对象地址赋给引用 如果顺序变成了 1->3->2就会导致某个线程获取到的对象没有初始化)
singletonDoubleCheck = new SingletonDoubleCheck();
}
}
}
return singletonDoubleCheck;
}
}
SingletonObject 使用类加载器本身就实现了线程安全机制(类仅被加载一次)实现多线程下获取单个实例逻辑
public class SingletonObject {
//饥汉模式 天生就具有线程安全性,类加载器控制一个类只被加载一次
private static SingletonObject singletonObject = new SingletonObject();
//避免外部通过new来创建对象
private SingletonObject() {
}
public static SingletonObject getSingletonObj() {
//return singletonObject;
return Holder.INSTANCE;
}
//使用静态类建立单例,因为类只被加载器加载一次
//饱汉模式,使用的时候才创建,这样和double-check比起来不用加锁同步了
private static class Holder {
private static SingletonObject INSTANCE = new SingletonObject();
}
}
Client 测试类
/**
* @author duanyimiao
* @create 2018-10-19 10:28 PM
* @description
**/
public class Client {
public static void main(String[] args) {
SingletonDoubleCheck singletonDoubleCheck1 = SingletonDoubleCheck.getInstance();
SingletonDoubleCheck singletonDoubleCheck2 = SingletonDoubleCheck.getInstance();
System.out.println(String.format("by class loader only create one object", singletonDoubleCheck1 == singletonDoubleCheck2 ? "is" : "is not"));
SingletonObject singletonObject1 = SingletonObject.getSingletonObj();
SingletonObject singletonObject2 = SingletonObject.getSingletonObj();
System.out.println(String.format("by double check only create one object", singletonObject1 == singletonObject2 ? "is" : "is not"));
}
}
输出结果
by class loader is only create one object
by double check is only create one object