闲来无聊,自己写着玩,有更好的建议可以提出
饿汉式
饿汉式单列,可以理解为非常饥饿,当类加载时就加载当前类
属于多线程安全类,在类装载时就实例化
package com.demo.maipiao;
/**
* 饿汉式
*
* @author DONG
* date:2022-08-23
*/
public class Singleton {
private static Singleton singleton = new Singleton();
/**
* 私有构造方法
*/
private Singleton() {
}
/**
* 共有获取单例
* @return 单例
*/
public static Singleton getInstance() {
return singleton;
}
}
懒汉式
懒汉式就是我懒,你不要我就不加载,你要了我再加载
懒汉式(线程不安全)
不安全则为不加锁的情况下
/**
* 懒汉式-线程不安全
*
* @author DONG
* date:2022-08-23
*/
public class Singleton {
private static Singleton singleton;
/**
* 私有构造方法
*/
private Singleton() {
}
/**
* 共有获取单例
* @return 单例
*/
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
懒汉式(线程安全)
安全则为线程安全,与上相比仅仅使用了synchronized加锁,用在static的方法上代码锁的是当前类.class
/**
* 懒汉式-线程安全
*
* @author DONG
* date:2022-08-23
*/
public class Singleton {
private static Singleton singleton;
/**
* 私有构造方法
*/
private Singleton() {
}
/**
* 共有获取单例
* @return 单例
*/
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
双检锁/双重校验锁
进行两次效验
切记,加volatile 关键字,因为多线程访问volatile不会发生阻塞,不会引起上下文的切换和调度
/**
* 懒汉式-双检锁
*
* @author DONG
* date:2022-08-23
*/
public class Singleton {
private static volatile Singleton singleton;
/**
* 私有构造方法
*/
private Singleton() {
}
/**
* 共有获取单例
* @return 单例
*/
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if ((singleton == null)) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
双检锁对属性进行了两次效验,为什么会需要需要效验两次???
未双重锁时:
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
当A线程走过了if判断,此时类还没加载,当if代码块里得还没运行时,此时会
B线程进来了,发现singleton还没加载, 顺利就进入了代码块里
加双重锁时:
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if ((singleton == null)) {
singleton = new Singleton();
}
}
}
return singleton;
}
当A线程和B线程同时走到了第一次的if判断,当前的类还未加载,那么AB线程此时都已经过了第一次if判断。
此时当A线程进入了synchronized锁住的代码块里,这时B已经不能进入,当A线程运行锁住的代码块后,B线程进入,判断singleton是否为null,此时A线程已经运行完了代码,那么就不会进入第二次判断的代码块里了
升级版(防止反射加载)
防止通过反射获取类
在私有构造中加个boolean类型的标识,当类第一次构建的时,flag=true,再次构造则抛出异常
/**
* 双重检查锁,懒汉式加载-防反射
*
* @author DONG
* date:2022-08-23
*/
public class Singleton {
private static boolean flag = false;
private static volatile Singleton instance;
/**
* 私有构造方法
*/
private Singleton() {
// 预防反射创建多个对象
synchronized (Singleton.class) {
if (flag) {
throw new RuntimeException("不能创建多个对象");
}
flag = true;
}
}
/**
* 公有单列提供
*
* @return 单列
*/
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}