首页 文章 精选 留言 我的

精选列表

搜索[安全],共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源创计划”,欢迎正在阅读的你也加入,一起分享。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

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

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

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

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册