单例模式
前言: 单例模式实际在我的理解里很简单,而且是一个老生常谈的问题了。可以今天翻到这里突然就发现单例模式都有哪些实现方式,线程安全性。。。我居然说不出来!所以特此进行记录,自学笔记专开一个杂项,用以记录纯基础知识。杂项的部分文章规范将不再统一,仅为了记录知识用以以后翻阅。
一、饿汉式
饿汉式线程安全但是会一定程度浪费资源。
// 饿汉式单例
public class Hungry {
//所有的都先创建好
private byte[] data1 = new byte[1024*1024];
private byte[] data2 = new byte[1024*1024];
private byte[] data3 = new byte[1024*1024];
private byte[] data4 = new byte[1024*1024];
private Hungry(){
}
private final static Hungry hungry = new Hungry();
public static Hungry getInstance(){
return hungry;
}
}
二、懒汉式
懒汉式线程不安全,只有用的时候才生成。
// 懒汉式单例
public class LazyMan {
private LazyMan(){
synchronized (LazyMan.class){
if (lazyMan != null){
throw new RuntimeException("避免反射导致单例失效!");// 抛出一个运行时异常
}
}
}
private volatile static LazyMan lazyMan;
// 双重检测锁模式 懒汉式 DCL懒汉式
public static LazyMan getInstance(){
if (lazyMan == null){
// 加锁,类只有一个。
synchronized (LazyMan.class){
if (lazyMan == null)
lazyMan = new LazyMan();// 不是原子性操作
/*
这个new操作
1、分配内存空间
2、执行构造方法,初始化对象
3、把这个对象指向这个空间
但是这三步不是顺序操作
如果 执行顺序为132
当空间被占用时 其他线程会认为 lazyMan != null
但如果2未执行完则相当于初始化未完成
后面return会有问题
所以要在单例对象上加 volatile 实现可见性和禁止指令重排序,从而保证安全性
(轻量级的同步机制 1.保证可见性 2.禁止指令重排 3.不保证原子性 4.volatile只能作用于属性)
*/
}
}
return lazyMan;
}
}
反射会使单例模式变得不安全
三、内部类
// 静态内部类
public class Holder {
private Holder() {
}
public static Holder getInstance() {
return InnerClass.holder;
}
public static class InnerClass{
private static final Holder holder = new Holder();
}
}