多线程下安全的单例模式(双重校验锁实现,登记者模式实现,利用内部类实现,利用枚举实现)
来源:互联网 发布:老版书旗小说软件 编辑:程序博客网 时间:2024/06/05 10:31
首先我们来看一下什么是懒汉模式:就是实例对象是在你需要的时候才会创建,也就是说当你第一次调用静态方法getInstance() 时它才会帮创你建实例对象。
下面来看一下懒汉模式的线程安全的写法即双重校验锁的懒汉模式
public class TwoCheckSingleInstance { private static volatile TwoCheckSingleInstance instance; private TwoCheckSingleInstance(){} public static TwoCheckSingleInstance getInstatnce(){ //如果不为空可以直接返回,不需要进行加锁处理。这样可以提高效率 if(instance!=null){ return instance; } synchronized(TwoCheckSingleInstance.class){ if(instance==null){ instance=new TwoCheckSingleInstance(); } return instance; } }}
有上面代码可以看出,虽然双重校验可以提高效率,但因为synchronize锁住的还是类对象,是一个类锁。显然这样虽然可以防止多线程环境下出现不安全的情况,但是效率确是比锁住实例对象,即对象锁来的低的多。看到这里有人会说这太简单了吧只要把synchronize(TwoCheckSingleInstance.class)改成synchronize(this)不就行了,如果你有这种想法的话,我只想说,请你回炉重造吧,看清楚这是一个静态方法,所以不可能有this 或super 这种的实例对象引用的。
那问题来了那该怎么获取了,别急,本文的主角登场了。
要实现登记者化的单例模式,我们需要一个登记模板,它是一个通用模板
代码如下
//登记模板,减少重复代码public abstract class registrantSingleInstance<T> { private T instance; //交给子类具体实现 protected abstract T create(); //多线程下安全的获取单例对象的重复代码 //类似懒汉的双重校验锁,但它锁的是对象,不是整个类,是对象锁,不是类锁 //final 是为了防止子类复写该方法 protected final T getInstance(){ if (instance!=null){ return instance; } synchronized (this) { if(instance==null){ instance= create(); } return instance; } }}
有了登记模板后,我们就可以利用该模板,来构建我们的单例类
//来访者或者是要单例化的类public class Student { private Student(){ } //向登记模板,登记来访者 private static registrantSingleInstance<Student> instance=new registrantSingleInstance<Student>(){ @Override public Student create() { return new Student(); } }; //获取来访者的单例 public static Student getInstance(){ return instance.getInstance(); }}
我们来看一下性能到底提升了多少
public class SingleTest{ public static void main(String[] args) { System.out.println("------------------------------>双重校验的懒汉模式"); long start1 =System.currentTimeMillis(); for(int i=0;i<1000000000;i++){ TwoCheckSingleInstance.getInstatnce(); } System.out.println(System.currentTimeMillis()-start1+"毫秒"); System.out.println("------------------------------>登记者模式"); long start2 =System.currentTimeMillis(); //Student.getStudent(); for(int i=0;i<1000000000;i++){ Student.getInstance(); } System.out.println(System.currentTimeMillis()-start2+"毫秒"); }}
下面是运行截图,你们测试的时候结果可不一样,当大体上都是,登记者模式的单例比双重校验的快
登记者模式的单例,它不仅拥有懒汉的优点,而且还非常简洁,代码复用率就非常高了,特别是要有多个单例化的类时就可以使用登记者模式的单例。如果单例化的类比较少的话,可以用内部类实现的单例,和用枚举实现的单例,这俩种都是利用了类加载机制来保证多线程下的获取单例的安全性。
用内部类实现单例代码如下:
public class InnerSingleInstance { private InnerSingleInstance(){}; private static class Instance{ private final static InnerSingleInstance instance=new InnerSingleInstance(); } public static InnerSingleInstance getInstance(){ return Instance.instance; }}
枚举实现单例代码如下:
public enum EnumSingleInstance { Instance; private Tess instance; private EnumSingleInstance(){ instance=new Tess(); } public Tess getInstance(){ return instance; }}
执行效率排行如下:
枚举实现单例 >(快于)用内部实现单例 >(快于) 用登记者模式实现的单例 >(快于)双重校验实现的单例
- 多线程下安全的单例模式(双重校验锁实现,登记者模式实现,利用内部类实现,利用枚举实现)
- 利用静态内部类实现的单例模式
- 利用双重检查加锁机制实现线程安全的单例模式
- Java 利用枚举实现单例模式
- Java 利用枚举实现单例模式
- Java 利用枚举实现单例模式
- Java 利用枚举实现单例模式
- 单例模式-静态内部类的实现(线程安全)
- 单例模式的五种写法:饿汉,懒汉, 双重校验锁,静态内部类,枚举
- 理解单例设计模式(饿汉式,懒汉式,静态内部类,枚举,双重校验锁)
- 单例模式静态内部类实现线程安全。
- 单例模式实现延迟加载在多线程下的思考(双检锁和内部类)
- 单例模式--理解静态内部类实现线程安全的单例模式
- 最安全的单例模式--java使用内部类实现单例模式
- 最安全的单例模式--java使用内部类实现单例模式
- 内部类实现多线程环境中的单例模式
- 多线程单例模式的安全实现
- 单例模式的另一种实现(内部类)
- Maven —— 二、大体认识pom.xml 中元素
- android系统定制功能:定时重启
- Hibernate之类级别查询
- windows server 2012安装zabbix客户端
- 匿名函数(闭包)
- 多线程下安全的单例模式(双重校验锁实现,登记者模式实现,利用内部类实现,利用枚举实现)
- 剑指offer_发散思维---求1+2+3+...+n
- MyBatis使用Collection查询多对多或一对多结果集bug
- ubuntu16.04 SSH服务器与win 之间互传文件以及服务器搭建
- React学习之进阶ref的必要性(十三)
- Ehcache缓存技术详解
- Express 入门
- 表单中涉及到的日期控件以及日期时间控件遇到的坑。
- lintcode:哈希函数