单例模式
单例是⼀种设计模式。单例模式是指整个程序中⼀个类只能有⼀个对象。
static修饰一个变量之后,这个变量就从⼀个普通的成员变量、属性变成了类对象的成员变量,⽽在JVM中⼀个类只有⼀个类对象,从⽽保证了static变量的唯⼀性。
饿汉模式
类一加载就完成初识化的方式成为饿汉模式
public class SingletonHungry {
// 用static修饰变量,变量就是自己,并且赋初始值
private static SingletonHungry instance = new SingletonHungry();
// 构造方法私有化
private SingletonHungry() {}
/**
* 提供一个对外获取实例对象的方法
* @return instance
*/
public static SingletonHungry getInstance () {
return instance;
}
}
public class Demo01_Singleton {
public static void main(String[] args) {
// 通过静态方法调用,获取单例
SingletonHungry singleton01 = SingletonHungry.getInstance();
SingletonHungry singleton02 = SingletonHungry.getInstance();
SingletonHungry singleton03 = SingletonHungry.getInstance();
// 分别打印
System.out.println(singleton01);
System.out.println(singleton02);
System.out.println(singleton03);
}
}
懒汉模式
为了避免程序启动的时候浪费过多的系统资源,当程序使用这个对象时再进行初始化,把这种模式叫做“懒汉模式。
public class SingletonLazy {
// 定义一个类成员变量
private static SingletonLazy instance = null;
// 构造方法私有化
private SingletonLazy() {
}
public static SingletonLazy getInstance() {
// 在获取的成员变量的时候,判断一下是否已经初始创建
// 如果没有创建则创建出来
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
懒汉模式在多线程环境下,可能出现线程安全的问题,那么就需要使用synchronized包裹初始化的代码块。
public class SingletonLazy {
// 定义一个类成员变量
private static SingletonLazy instance = null;
// 构造方法私有化
private SingletonLazy() {
}
public static SingletonLazy getInstance() {
// 在获取的成员变量的时候,判断一下是否已经初始创建
// 如果没有创建则创建出来
synchronized (SingletonLazy.class) {
if (instance == null) {
instance = new SingletonLazy();
}
}
return instance;
}
}
初识化代码只执行一次,后续的线程在调用getInstance()时,依然会产生锁竞争,频繁的进行用户态和内存态之间的切换,非常浪费计算机资源。因此可以引进double check lock(DCL)的方式,在外层加一个非空校验,避免了无用
public class SingletonDCL {
// 定义一个类成员变量
private volatile static SingletonDCL instance;
// 构造方法私有化
private SingletonDCL() {
}
public static SingletonDCL getInstance() {
// 为了让后面的线程不再获取锁,避免了锁竞争造成的资源浪费
if (instance == null) {
synchronized (SingletonDCL.class) {
// 完成初始化操作,只执行一次
if (instance == null) {
instance = new SingletonDCL();
}
}
}
// 返回实例对象
return instance;
}
}
public class Demo04_SingletonDCL {
public static void main(String[] args) {
// 创建多个线程,并获取单例对象
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(()->{
// 获取单例对象,并打印
SingletonDCL singletonDCL = SingletonDCL.getInstance();
System.out.println(singletonDCL);
});
thread.start();
}
}
}