单列中的四种实现方式
方式一:普通的饿汉式和懒汉式单例模式
三部曲:
(1)私有化构造方法 (2)私有化静态本类对象作为属性 (3)提供公有静态方法获取本类对象
1.普通的饿汉式(静态的内部)
public class Client { public static void main(String[] args) { Singleton.getInstance(); } static class Singleton { private static final Singleton instance = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return instance; } } }
2.饿汉式静态代码块单例模式
//饿汉式静态代码块单例模式 public class HungryStaticSingleton { private static final HungryStaticSingleton instance; static { instance = new HungryStaticSingleton(); } private HungryStaticSingleton(){} public static HungryStaticSingleton getInstance(){ return instance; } }
3.饿汉式静态代码块单例模式
/** * 优点:执行效率高,性能高,没有任何的锁 * 缺点:某些情况下,可能会造成内存浪费 */ //饿汉式静态代码块单例模式 public class HungrySingleton { private static final HungrySingleton instance = new HungrySingleton(); private HungrySingleton(){} public static HungrySingleton getInstance(){ return instance; } }
二:懒汉式
1.懒汉式单例模式在外部需要使用的时候才进行实例化,这种是线程不安全的,如果多个线程同时并发访问,假设多个线程同时都进入到了 if(instance == null){}条件判断里面,那么就会同时创建多个对象。
/** * 优点:节省了内存,线程安全 * 缺点:性能低 */ //懒汉式单例模式在外部需要使用的时候才进行实例化 public class LazySimpleSingletion { //静态块,公共内存区域 private static LazySimpleSingletion instance; private LazySimpleSingletion(){} public synchronized static LazySimpleSingletion getInstance(){ if(instance == null){ instance = new LazySimpleSingletion(); } return instance; } }
2.单次检查机制(使用类锁),这种也是有缺点的,使用的 synchronized 关键字,严重的影响了性能.
public class Singleton { private static Singleton instance = null; public static Singleton getInstance() { synchronized (Singleton.class) { if(null == instance) { instance = new Singleton(); } } return instance; } }
3.利用双重检查机制(DCL) ,保证了线程的安全
/** * 优点:性能高了,线程安全了 * 缺点:可读性难度加大,不够优雅 */ public class LazyDoubleCheckSingleton { private volatile static LazyDoubleCheckSingleton instance; private LazyDoubleCheckSingleton(){} public static LazyDoubleCheckSingleton getInstance(){ //检查是否要阻塞 if (instance == null) { synchronized (LazyDoubleCheckSingleton.class) { //检查是否要重新创建实例 if (instance == null) { instance = new LazyDoubleCheckSingleton(); //指令重排序的问题 } } } return instance; } }
4.自认为史上最牛的单例模式的实现方式 (这里有个技术上的高深的点技术基础点,说到底还是技术的基础和本质)----->>>> 利用了Java本身语法特点,内部类默认不加载
/* ClassPath : LazyStaticInnerClassSingleton.class LazyStaticInnerClassSingleton$LazyHolder.class 优点:写法优雅,利用了Java本身语法特点,性能高,避免了内存浪费,不能被反射破坏 缺点:不优雅 */ //这种形式兼顾饿汉式单例模式的内存浪费问题和synchronized的性能问题 //完美地屏蔽了这两个缺点 //自认为史上最牛的单例模式的实现方式 public class LazyStaticInnerClassSingleton { //使用LazyInnerClassGeneral的时候,默认会先初始化内部类 //如果没使用,则内部类是不加载的 private LazyStaticInnerClassSingleton(){ if(LazyHolder.INSTANCE != null){ throw new RuntimeException("不允许创建多个实例"); } } //每一个关键字都不是多余的,static是为了使单例的空间共享,保证这个方法不会被重写、重载 private static LazyStaticInnerClassSingleton getInstance(){ //在返回结果以前,一定会先加载内部类 return LazyHolder.INSTANCE; } //利用了Java本身语法特点,内部类默认不加载 private static class LazyHolder{ private static final LazyStaticInnerClassSingleton INSTANCE = new LazyStaticInnerClassSingleton(); } }
5.枚举法
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;} }
6.序列化一个单列对象
import java.io.Serializable; public class SeriableSingleton implements Serializable { //序列化 //把内存中对象的状态转换为字节码的形式 //把字节码通过IO输出流,写到磁盘上 //永久保存下来,持久化 //反序列化 //将持久化的字节码内容,通过IO输入流读到内存中来 //转化成一个Java对象 public final static SeriableSingleton INSTANCE = new SeriableSingleton(); private SeriableSingleton(){} public static SeriableSingleton getInstance(){ return INSTANCE; } private Object readResolve(){ return INSTANCE;} }
7.手动创建一个单列对象(根据类名来创建)
public class ContainerSingleton { private ContainerSingleton(){} private static Map<String,Object> ioc = new ConcurrentHashMap<String, Object>(); public static Object getInstance(String className){ Object instance = null; if(!ioc.containsKey(className)){ try { instance = Class.forName(className).newInstance(); ioc.put(className, instance); }catch (Exception e){ e.printStackTrace(); } return instance; }else{ return ioc.get(className); } } }
8.ThreadLocal设置单列
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(); } }