关于设计模式它主要考察的是类跟类的关系,为了达到某一个目标有固定的套路,比如说之前的装饰模式进行装饰,代理模式进行代理。那单例模式的目标是对外只有一个对象,对内怎么创建对象不管,对外你只能用一个对象,这就像中国的计划生育,你私底下可以偷偷的生,但是对外你就上报一个孩子,这就是独生子女。所以这里就是给类进行计划生育,对外只有一个对象。
关于单例模式有很多的写法,比如懒汉式、饿汉式,这里讲的double-checking、dcl或者枚举等等很多种。
这里主要是讲解怎么使用volatile、double-checking进行锁定达到单例。
这个单例在生活中还是随处可见的,比如说电脑中的任务管理器,一台电脑只有一个任务管理器,做web开发的时候的计数器,或者我们写的配置文件,比如说log4j,它内部都是单例,数据库的连接池,以及序列号的生成等等都会用到单例。
这个单例模式在高级框架Spring里面肯定能够见到。
现在就是用double-checking、volatile、synchronized实现单例。
volatile可以避免指令重排。
package com.sxt.others;
/**
* DCL单例模式: 懒汉式套路基础上加入并发控制,保证在多线程环境下,对外存在一个对象
* 1、构造器私有化 -->避免外部new构造器
* 2、提供私有的静态属性 -->存储对象的地址
* 3、提供公共的静态方法 --> 获取属性
*
* @author
*
*/
public class DoubleCheckedLocking {
//2、提供私有的静态属性
//没有volatile其他线程可能访问一个没有初始化的对象
private static volatile DoubleCheckedLocking instance;
//1、构造器私有化
private DoubleCheckedLocking() {
}
//3、提供公共的静态方法 --> 获取属性
public static DoubleCheckedLocking getInstance() {
//再次检测
if(null!=instance) { //避免不必要的同步 ,已经存在对象
return instance;
}
synchronized(DoubleCheckedLocking.class) {
if(null == instance) {
instance = new DoubleCheckedLocking();
//1、开辟空间 //2、初始化对象信息 //3、返回对象的地址给引用
}
}
return instance;
}
public static DoubleCheckedLocking getInstance1(long time) {
if(null == instance) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new DoubleCheckedLocking();
//1、开辟空间 //2、初始化对象信息 //3、返回对象的地址给引用
}
return instance;
}
public static void main(String[] args) {
Thread t = new Thread(()->{
System.out.println(DoubleCheckedLocking.getInstance());
}) ;
t.start();
System.out.println(DoubleCheckedLocking.getInstance());
}
}