懒汉式
静态属性
/**
* @Author jyl
* @Date 2021/12/10 8:41
* @Version 1.0
*/
//饿汉式单例
// 它是在类加载的时候就立即初始化,并且创建单例对象
//优点:没有加任何的锁、执行效率比较高,
//在用户体验上来说,比懒汉式更好
//缺点:类加载的时候就初始化,不管你用还是不用,我都占着空间
//浪费了内存,有可能占着茅坑不拉屎
//绝对线程安全,在线程还没出现以前就是实例化了,不可能存在访问安全问题
public class HungrySingleton {
public HungrySingleton(){}
public static final HungrySingleton hungrySingleton = new HungrySingleton();
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
静态静态块
/**
* @Author jyl
* @Date 2021/12/10 8:45
* @Version 1.0
* 饿汉式静态块单例
*/
public class HungryStaticSingleton {
public static final HungryStaticSingleton HungryStaticSingleton ;
public HungryStaticSingleton(){}
static {
HungryStaticSingleton = new HungryStaticSingleton();
}
public static HungryStaticSingleton getInstance(){
return HungryStaticSingleton;
}
}
懒汉式
简单单例
**
* @Author jyl
* @Date 2021/12/10 8:49
* @Version 1.0
* 懒汉式单例
* 在外部需要使用的时候才进行实例化
* 有可能锁住整个类
*/
public class LazySimpleSingleton {
private LazySimpleSingleton(){}
//静态块,公共内存区域
private static LazySimpleSingleton lazy = null;
public synchronized static LazySimpleSingleton getInstance(){
if(lazy==null) {
lazy = new LazySimpleSingleton();
return lazy;
}
return lazy;
}
}
内部类单例
/**
* @Author jyl
* @Date 2021/12/10 9:05
* @Version 1.0
*/
//懒汉式单例
//这种形式兼顾饿汉式的内存浪费,也兼顾synchronized性能问题
//完美地屏蔽了这两个缺点
//史上最牛B的单例模式的实现方式
public class LazyInnerClassSingleton {
/* 默认使用LazyInnerClassGeneral的时候,会先初始化内部类
如果没使用的话,内部类是不加载的
而这个内部类LazyHolder 在需要外部调用的情况才需要加载巧妙了利用率内部类的特性
jvm底层逻辑完美避免了线程安全的问题
*/
private LazyInnerClassSingleton(){
/*防止反射时候使用class创建*/
if (LazyHolder.lazy !=null){
throw new RuntimeException("不允许创建多个实例");
}
}
//默认不加载
private static class LazyHolder{
//每一个关键字都不是多余的
//static 是为了使单例的空间共享
//final 保证这个方法不会被重写,重载
private static final LazyInnerClassSingleton lazy = new LazyInnerClassSingleton();
}
}
双锁单例
**
* @Author jyl
* @Date 2021/12/10 9:16
* @Version 1.0
* 双锁单例
*/
public class LazyDoubleCheckSingleton {
/*防止指令重排*/
private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton;
private LazyDoubleCheckSingleton(){}
public static LazyDoubleCheckSingleton getInstance(){
if(lazyDoubleCheckSingleton==null) {
synchronized (LazyDoubleCheckSingleton.class) {
if(lazyDoubleCheckSingleton==null) {
return new LazyDoubleCheckSingleton();
}
}
}
return lazyDoubleCheckSingleton;
}
}
客户端
多线程任务
/**
* @Author jyl
* @Date 2021/12/10 10:35
* @Version 1.0
* 多线程任务
*/
public class ExectorThread implements Runnable {
public void run() {
LazySimpleSingleton singleton = LazySimpleSingleton.getInstance();
System.out.println(Thread.currentThread().getName() + ":" + singleton);
}
}
简单调用
/**
* @Author jyl
* @Date 2021/12/10 10:41
* @Version 1.0
* 简单lazy测试类
*/
public class LazySimpleSingletonTest {
public static void main(String[] args) {
Thread t1 = new Thread(new ExectorThread());
Thread t2 = new Thread(new ExectorThread());
t1.start();
t2.start();
System.out.println("End");
}
}
无聊的反射破坏
**
* @Author jyl
* @Date 2021/12/10 10:37
* @Version 1.0
* 这个是模仿我们懒加载内部类被反射调用产生的单例被破坏的案例
* 解决办法是在构造方法增加判断抛出异常
*/
public class LazyInnerClassSingletonTest {
public static void main(String[] args) {
try{
//很无聊的情况下,进行破坏
Class<?> clazz = LazyInnerClassSingleton.class;
//通过反射拿到私有的构造方法
Constructor c = clazz.getDeclaredConstructor(null);
//强制访问可以访问到私有的方法
c.setAccessible(true);
//暴力初始化
Object o1 = c.newInstance();
//调用了两次构造方法,相当于new了两次
//犯了原则性问题,
Object o2 = c.newInstance();
System.out.println(o1 == o2);
// Object o2 = c.newInstance();
}catch (Exception e){
e.printStackTrace();
}
}
}
注册式
枚举单例
/**
* @Author jyl
* @Date 2021/12/10 11:36
* @Version 1.0
*/
public enum EnumSingleton {
INSTANCE;
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static EnumSingleton getInstance(){
return INSTANCE;
}
}
容器单例
/**
* @Author jyl
* @Date 2021/12/13 9:44
* @Version 1.0
* Spring中的做法,就是用这种注册式单例
*/
public class ContainerSingleton {
private ContainerSingleton(){}
private static Map<String,Object> ioc = new ConcurrentHashMap<String,Object>();
public static Object getInstance(String className){
synchronized (ioc) {
if (!ioc.containsKey(className)) {
Object obj = null;
try {
obj = Class.forName(className).newInstance();
ioc.put(className, obj);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
} else {
return ioc.get(className);
}
}
}
}
客户端
/**
* @Author jyl
* @Date 2021/12/10 11:37
* @Version 1.0
*/
public class EnumSingletonTest {
// /*反序列化破坏枚举单例*/
// public static void main(String[] args) {
// try {
// EnumSingleton instance1 = null;
//
// EnumSingleton instance2 = EnumSingleton.getInstance();
// instance2.setData(new Object());
//
// FileOutputStream fos = new FileOutputStream("EnumSingleton.obj");
// ObjectOutputStream oos = new ObjectOutputStream(fos);
// oos.writeObject(instance2);
// oos.flush();
// oos.close();
//
// FileInputStream fis = new FileInputStream("EnumSingleton.obj");
// ObjectInputStream ois = new ObjectInputStream(fis);
// instance1 = (EnumSingleton) ois.readObject();
// ois.close();
//
// System.out.println(instance1.getData());
// System.out.println(instance2.getData());
// System.out.println(instance1.getData() == instance2.getData());
//
// }catch (Exception e){
// e.printStackTrace();
// }
// }
/*反射破坏枚举单例*/
public static void main(String[] args) {
try {
Class clazz = EnumSingleton.class;
Constructor c = clazz.getDeclaredConstructor(String.class,int.class);
c.setAccessible(true);
EnumSingleton enumSingleton = (EnumSingleton)c.newInstance("Tom",666);
}catch (Exception e){
e.printStackTrace();
}
}
}
线程单例
/**
* @Author jyl
* @Date 2021/12/13 9:53
* @Version 1.0
* 线程安全单例
*/
public class ThreadLocalSingleton {
private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance =
new ThreadLocal<ThreadLocalSingleton>(){
@Override
protected ThreadLocalSingleton initialValue() {
return new ThreadLocalSingleton();
}
};
private ThreadLocalSingleton(){}
public static ThreadLocalSingleton getInstance(){
return threadLocalInstance.get();
}
}
客户端
多线程类
/**
* @Author jyl
* @Date 2021/12/13 9:56
* @Version 1.0
*/
public class ExectorThread implements Runnable {
public void run() {
ThreadLocalSingleton singleton = ThreadLocalSingleton.getInstance();
System.out.println(Thread.currentThread().getName() + ":" + singleton);
}
}
测试
**
* @Author jyl
* @Date 2021/12/13 9:55
* @Version 1.0
* 线程单例测试类
*/
public class ThreadLocalSingletonTest {
public static void main(String[] args) {
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
Thread t1 = new Thread(new ExectorThread());
Thread t2 = new Thread(new ExectorThread());
t1.start();
t2.start();
System.out.println("End");
}
}
序列化
/**
* @Author jyl
* @Date 2021/12/10 10:00
* @Version 1.0
* 反序列化时导致单例破坏
*/
public class SeriableSingleton implements Serializable {
//序列化就是说把内存中的状态通过转换成字节码的形式
//从而转换一个IO流,写入到其他地方(可以是磁盘、网络IO)
//内存中状态给永久保存下来了
//反序列化
//讲已经持久化的字节码内容,转换为IO流
//通过IO流的读取,进而将读取的内容转换为Java对象
//在转换过程中会重新创建对象new
public final static SeriableSingleton INSTANCE = new SeriableSingleton();
private SeriableSingleton(){}
public static SeriableSingleton getInstance(){
return INSTANCE;
}
/*重写了readResolve 序列化序列化的对象意味着还是创建了两次发生在jvm层面之间反序列化的对象会被gc回收*/
private Object readResolve(){
return INSTANCE;
}
}
客户端
/**
* @Author jyl
* @Date 2021/12/10 11:04
* @Version 1.0
*/
public class SeriableSingletonTest {
public static void main(String[] args) {
SeriableSingleton s1 = null;
SeriableSingleton s2 = SeriableSingleton.getInstance();
FileOutputStream fos = null;
try {
fos = new FileOutputStream("SeriableSingleton.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(s2);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("SeriableSingleton.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
s1 = (SeriableSingleton)ois.readObject();
ois.close();
System.out.println(s1);
System.out.println(s2);
System.out.println(s1 == s2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
为啥加上 private Object readResolve(){ 就可以防止序列化破坏类的单例呢 看源码
未完待续