首页 文章 精选 留言 我的

精选列表

搜索[安全],共10000篇文章
优秀的个人博客,低调大师

java安全编码指南之:锁的双重检测

简介 双重检测锁定模式是一种设计模式,我们通过首次检测锁定条件而不是实际获得锁从而减少获取锁的开销。 双重检查锁定模式用法通常用于实现执行延迟初始化的单例工厂模式。延迟初始化推迟了成员字段或成员字段引用的对象的构造,直到实际需要才真正的创建。 但是我们需要非常小心的使用双重检测模式,以避免发送错误。 单例模式的延迟加载 先看一个在单线程正常工作的单例模式: public class Book { private static Book book; public static Book getBook(){ if(book==null){ book = new Book(); } return book; }} 上面的类中定义了一个getBook方法来返回一个新的book对象,返回对象之前,我们先判断了book是否为空,如果不为空的话就new一个book对象。 初看起来,好像没什么问题,我们仔细考虑一下: book=new Book()其实一个复杂的命令,并不是原子性操作。它大概可以分解为1.分配内存,2.实例化对象,3.将对象和内存地址建立关联。 在多线程环境中,因为重排序的影响,我们可能的到意向不到的结果。 最简单的办法就是加上synchronized关键字: public class Book { private static Book book; public synchronized static Book getBook(){ if(book==null){ book = new Book(); } return book; }} double check模式 如果要使用double check模式该怎么做呢? public class BookDLC { private static BookDLC bookDLC; public static BookDLC getBookDLC(){ if(bookDLC == null ){ synchronized (BookDLC.class){ if(bookDLC ==null){ bookDLC=new BookDLC(); } } } return bookDLC; }} 我们先判断bookDLC是否为空,如果为空,说明需要实例化一个新的对象,这时候我们锁住BookDLC.class,然后再进行一次为空判断,如果这次不为空,则进行初始化。 那么上的代码有没有问题呢? 有,bookDLC虽然是一个static变量,但是因为CPU缓存的原因,我们并不能够保证当前线程被赋值之后的bookDLC,立马对其他线程可见。 所以我们需要将bookDLC定义为volatile,如下所示: public class BookDLC { private volatile static BookDLC bookDLC; public static BookDLC getBookDLC(){ if(bookDLC == null ){ synchronized (BookDLC.class){ if(bookDLC ==null){ bookDLC=new BookDLC(); } } } return bookDLC; }} 静态域的实现 public class BookStatic { private static BookStatic bookStatic= new BookStatic(); public static BookStatic getBookStatic(){ return bookStatic; }} JVM在类被加载之后和被线程使用之前,会进行静态初始化,而在这个初始化阶段将会获得一个锁,从而保证在静态初始化阶段内存写入操作将对所有的线程可见。 上面的例子定义了static变量,在静态初始化阶段将会被实例化。这种方式叫做提前初始化。 下面我们再看一个延迟初始化占位类的模式: public class BookStaticLazy { private static class BookStaticHolder{ private static BookStaticLazy bookStatic= new BookStaticLazy(); } public static BookStaticLazy getBookStatic(){ return BookStaticHolder.bookStatic; }} 上面的类中,只有在调用getBookStatic方法的时候才会去初始化类。 ThreadLocal版本 我们知道ThreadLocal就是Thread的本地变量,它实际上是对Thread中的成员变量ThreadLocal.ThreadLocalMap的封装。 所有的ThreadLocal中存放的数据实际上都存储在当前线程的成员变量ThreadLocal.ThreadLocalMap中。 如果使用ThreadLocal,我们可以先判断当前线程的ThreadLocal中有没有,没有的话再去创建。 如下所示: public class BookThreadLocal { private static final ThreadLocal<BookThreadLocal> perThreadInstance = new ThreadLocal<>(); private static BookThreadLocal bookThreadLocal; public static BookThreadLocal getBook(){ if (perThreadInstance.get() == null) { createBook(); } return bookThreadLocal; } private static synchronized void createBook(){ if (bookThreadLocal == null) { bookThreadLocal = new BookThreadLocal(); } perThreadInstance.set(bookThreadLocal); }} 本文分享自微信公众号 - 程序那些事(flydean-tech)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册