java设计模式_单例模式
单例模式
核心作用:
- 保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
常见的几种单例模式实现方式
- 饿汉式(线程安全,调用效率高。但是不能延时加载。)
- 懒汉式(线程安全,调用效率不高。但是可以延时加载)
- 双重检测锁式(由于JVM底层内部模型原因,偶尔会出现问题。不建议使用)
- 静态内部类式(线程安全,调用效率高,可以延时加载)
- 枚举单例(线程安全,调用效率高。不能延时加载)
饿汉式实现:
package com.yibobo.singleton; /** * 测试饿汉式的单例模式 * @author pyb www.yibobo.top */ public class SingletonDemo01 { //类初始化时,立即加载对象!由于加载类时线程是天然安全的所以无需同步 private static SingletonDemo01 s = new SingletonDemo01(); private SingletonDemo01(){}//私有化构造器 //方法没有同步,效率高! public static SingletonDemo01 getInstance(){ return s; } }
package com.yibobo.singleton; public class Test { public static void main(String[] args) { SingletonDemo01 s1 = SingletonDemo01.getInstance(); SingletonDemo01 s2 = SingletonDemo01.getInstance(); System.out.println(s1==s2);//结果为true } }
饿汉式单例模式代码中,static变量会在类装载时初始化,此时也不会涉及多个线程对象访问该对象的问题。虚拟机保证只会装载一次该类,肯定不会发生并发访问的问题,因此可以省略synchronize关键字。
问题:如果只是加载该类,而不是要调用getInstance()方法,甚至永远没有调用,则会造成资源浪费。
懒汉式实现:
package com.yibobo.singleton; /** * 测试懒汉式的单例模式 * @author pyb www.yibobo.top */ public class SingletonDemo02 { //类初始化时,并不初始化对象,延时加载,真正要用的时候在加载 private static SingletonDemo02 s; private SingletonDemo02(){}//私有化构造器 //在调用getInstance()方法时,在判定new不new //方法同步,调用效率较低 public static synchronized SingletonDemo02 getInstance(){ if (s == null){ s = new SingletonDemo02(); } return s; } }
延时加载!懒加载,真正用的时候才加载
问题:资源利用效率高了。但是,每次调用getInstance()方法时都要同步,并发效率较低
静态内部类式(也是一种懒加载方式):
package com.yibobo.singleton; /** * 测试静态内部类式的单例模式 * 这种方式线程安全、调用效率高且实现延时加载。需要延时加载时,静态内部类式好于懒汉式 * @author pyb www.yibobo.top */ public class SingletonDemo03 { private SingletonDemo03(){}//私有化构造器 //类加载的过程天然线程安全 private static class SingletonClassInstance{ private static final SingletonDemo03 instance = new SingletonDemo03(); } //无需同步,且用到时才会创建出对象。兼顾并发效率与延时加载 public static SingletonDemo03 getInstance(){ return SingletonClassInstance.instance; } }
要点:
- 外部类没有static属性,则不会像饿汉式那样立即加载对象。
- 只有真正调用getInstance(),才会加载静态内部类。加载类是是线程安全的。Instance是static final类型,保证了内存中只有一个实例存在且只能被赋值一次,从而保证了线程安全性
- 兼备了并发高效调用和延迟加载的优势!
枚举式:
package com.yibobo.singleton; /** * 测试枚举式的单例模式 * 由于枚举本身就是个单列,这种方式线程安全、调用效率高 * 但不能实现延时加载。在不需要延时加载的情况下枚举类好于饿汉式(但枚举用的人少) * @author pyb www.yibobo.top */ public enum SingletonDemo04 { INSTANCE; //下面就随便写这个类的方法 }
Double-Check双重锁定式,这种方式有问题,但是我看百度上说JDK1.5之后添加了一个关键字:volatile,这个可以解决双重锁定式的问题。自个研究吧
还是写一下
package com.yibobo.singleton; /** * 测试双重检查+锁的单例模式 * 这种方式线程安全、调用效率高且实现延时加载。 * @author pyb www.yibobo.top */ public class SingletonDemo05 { //类初始化时,并不初始化对象,延时加载,真正要用的时候在加载 private static volatile SingletonDemo05 s = null; private SingletonDemo05(){} //这个模式将同步内容下放到if内部,提高了执行的效率 //不必每次获取对象时都进行同步,只有第一次才同步,创建了以后就没必要了。 public static SingletonDemo05 getInstance() { if (s == null) { synchronized (SingletonDemo05.class) { if (s == null) { s = new SingletonDemo05(); } } } return s; } }