当前位置:首页 > 科技  > 软件

如何线程安全的使用 HashMap

来源: 责编: 时间:2024-06-05 17:44:50 231观看
导读这篇文章,我们聊聊线程安全使用 HashMap 的四种技巧。图片1.方法内部:每个线程创建单独的 HashMap如下图,tomcat 接收到到请求后,依次调用控制器 Controller、服务层 Service 、数据库访问层的相关方法。每次访问服务层方

这篇文章,我们聊聊线程安全使用 HashMap 的四种技巧。goU28资讯网——每日最新资讯28at.com

图片图片goU28资讯网——每日最新资讯28at.com

1.方法内部:每个线程创建单独的 HashMap

如下图,tomcat 接收到到请求后,依次调用控制器 Controller、服务层 Service 、数据库访问层的相关方法。goU28资讯网——每日最新资讯28at.com

每次访问服务层方法 serviceMethod 时,都会在方法体内部创建一个单独的 HashMap ,  将相关请求参数拷贝到 HashMap 里,然后调用 DAO 方法进行数据库操作。goU28资讯网——每日最新资讯28at.com

图片图片goU28资讯网——每日最新资讯28at.com

每个 HTTP 处理线程在服务层方法体内部都有自己的 HashMap 实例,在多线程环境下,不需要对 HashMap 进行任何同步操作。goU28资讯网——每日最新资讯28at.com

这也是我们使用最普遍也最安全的的方式,是 CRUD 最基本的操作。goU28资讯网——每日最新资讯28at.com

2.配置数据:初始化单线程写,后续只提供读

系统启动之后,我们可以将配置数据加载到本地缓存 HashMap 里 ,这些配置信息初始化之后,就不需要写入了,后续只提供读操作。goU28资讯网——每日最新资讯28at.com

图片图片goU28资讯网——每日最新资讯28at.com

上图中显示一个非常简单的配置类 SimpleConfig ,内部有一个 HashMap 对象 configMap 。构造函数调用初始化方法,初始化方法内部的逻辑是:将配置数据存储到 HashMap 中。goU28资讯网——每日最新资讯28at.com

SimpleConfig 类对外暴露了 getConfig 方法 ,当 main 线程初始化 SimpleConfig 对象之后,当其他线程调用  getConfig 方法时,因为只有读,没有写操作,所以是线程安全的。goU28资讯网——每日最新资讯28at.com

3.读写锁:读读不互斥,读写互斥,写写互斥

读写锁是一把锁分为两部分:读锁和写锁,其中读锁允许多个线程同时获得,而写锁则是互斥锁。goU28资讯网——每日最新资讯28at.com

它的规则是:读读不互斥,读写互斥,写写互斥,适用于读多写少的业务场景。goU28资讯网——每日最新资讯28at.com

我们一般都使用 ReentrantReadWriteLock ,该类实现了 ReadWriteLock 。ReadWriteLock 接口也很简单,其内部主要提供了两个方法,分别返回读锁和写锁 。goU28资讯网——每日最新资讯28at.com

public interface ReadWriteLock {    //获取读锁    Lock readLock();    //获取写锁    Lock writeLock();}

读写锁的使用方式如下所示:goU28资讯网——每日最新资讯28at.com

  1. 创建 ReentrantReadWriteLock 对象 , 当使用 ReadWriteLock 的时候,并不是直接使用,而是获得其内部的读锁和写锁,然后分别调用 lock / unlock 方法 ;
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
  1. 读取共享数据 ;
Lock readLock = readWriteLock.readLock();readLock.lock();try {   // TODO 查询共享数据} finally {   readLock.unlock();}
  1. 写入共享数据;
Lock writeLock = readWriteLock.writeLock();writeLock.lock();try {   // TODO 修改共享数据} finally {   writeLock.unlock();}

下面的代码展示如何使用 ReadWriteLock 线程安全的使用 HashMap :goU28资讯网——每日最新资讯28at.com

import java.util.HashMap;import java.util.Map;import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock;public class ReadWriteLockCache {      // 创建一个 HashMap 来存储缓存的数据    private Map<String, String> map = new HashMap<>();    // 创建读写锁对象    private ReadWriteLock rw = new ReentrantReadWriteLock();    // 放对象方法:向缓存中添加一个键值对    public void put(String key, String value) {        // 获取写锁,以确保当前操作是独占的        rw.writeLock().lock();        try {            // 执行写操作,将键值对放入 map            map.put(key, value);        } finally {            // 释放写锁            rw.writeLock().unlock();        }    }    // 取对象方法:从缓存中获取一个值    public String get(String key) {        // 获取读锁,允许并发读操作        rw.readLock().lock();        try {            // 执行读操作,从 map 中获取值            return map.get(key);        } finally {            // 释放读锁            rw.readLock().unlock();        }    }}

使用读写锁操作 HashMap 是一个非常经典的技巧,消息中间件 RockeMQ NameServer (名字服务)保存和查询路由信息都是通过这种技巧实现的。goU28资讯网——每日最新资讯28at.com

另外,读写锁可以操作多个 HashMap ,相比 ConcurrentHashMap 而言,ReadWriteLock 可以控制缓存对象的颗粒度,具备更大的灵活性。goU28资讯网——每日最新资讯28at.com

4.Collections.synchronizedMap : 读写均加锁

如下代码,当我们多线程使用 userMap 时,goU28资讯网——每日最新资讯28at.com

static Map<Long, User> userMap = Collections.synchronizedMap(new HashMap<Long, User>());

进入 synchronizedMap 方法:goU28资讯网——每日最新资讯28at.com

public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {       return new SynchronizedMap<>(m);}

图片图片goU28资讯网——每日最新资讯28at.com

SynchronizedMap 内部包含一个对象锁 Object mutex ,它本质上是一个包装类,将 HashMap 的读写操作重新实现了一次,我们看到每次读写时,都会用 synchronized 关键字来保证操作的线程安全。goU28资讯网——每日最新资讯28at.com

虽然 Collections.synchronizedMap 这种技巧使用起来非常简单,但是我们需要理解它的每次读写都会加锁,性能并不会特别好。goU28资讯网——每日最新资讯28at.com

5.总结

这篇文章,笔者总结了四种线程安全的使用 HashMap 的技巧。goU28资讯网——每日最新资讯28at.com

1)方法内部:每个线程创建单独的 HashMapgoU28资讯网——每日最新资讯28at.com

这是我们使用最普遍,也是非常可靠的方式。每个线程在方法体内部创建HashMap 实例,在多线程环境下,不需要对 HashMap 进行任何同步操作。goU28资讯网——每日最新资讯28at.com

2) 配置数据:初始化单线程写,后续只提供读goU28资讯网——每日最新资讯28at.com

中间件在启动时,会读取配置文件,将配置数据写入到 HashMap 中,主线程写完之后,以后不会再有写入操作,其他的线程可以读取,不会产生线程安全问题。goU28资讯网——每日最新资讯28at.com

3)读写锁:读读不互斥,读写互斥,写写互斥goU28资讯网——每日最新资讯28at.com

读写锁是一把锁分为两部分:读锁和写锁,其中读锁允许多个线程同时获得,而写锁则是互斥锁。goU28资讯网——每日最新资讯28at.com

它的规则是:读读不互斥,读写互斥,写写互斥,适用于读多写少的业务场景。goU28资讯网——每日最新资讯28at.com

使用读写锁操作 HashMap 是一个非常经典的技巧,消息中间件 RockeMQ NameServer (名字服务)保存和查询路由信息都是通过这种技巧实现的。goU28资讯网——每日最新资讯28at.com

4)Collections.synchronizedMap  : 读写均加锁goU28资讯网——每日最新资讯28at.com

Collections.synchronizedMap 方法使用了装饰器模式为线程不安全的 HashMap 提供了一个线程安全的装饰器类 SynchronizedMap。goU28资讯网——每日最新资讯28at.com

通过 SynchronizedMap 来间接的保证对 HashMap 的操作是线程安全,而 SynchronizedMap 底层也是通过 synchronized 关键字来保证操作的线程安全。goU28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-92144-0.html如何线程安全的使用 HashMap

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 2024 年你可以使用的十大 Node.js 现代特性

下一篇: 好坑,流水号重复竟然导致了一次生产事故!

标签:
  • 热门焦点
  • Find N3入网:最高支持16+1TB

    OPPO将于近期登场的Find N3折叠屏目前已经正式入网,型号为PHN110。本次Find N3在外观方面相比前两代有很大的变化,不再是小号的横向折叠屏,而是跟别的厂商一样采用了较为常见的
  • 5月iOS设备好评榜:iPhone 14仅排第43?

    来到新的一月,安兔兔的各个榜单又重新汇总了数据,像安卓阵营的榜单都有着比较大的变动,不过iOS由于设备的更新换代并没有那么快,所以相对来说变化并不大,特别是iOS好评榜,老款设
  • 六大权益!华为8月服务日开启:手机免费贴膜、维修免人工费

    8月5日消息,一年一度的华为开发者大会2023(Together)日前在松山湖拉开帷幕,与此同时,华为8月服务日也式开启,到店可享六大专属权益。华为用户可在华为商城Ap
  • 不容错过的MSBuild技巧,必备用法详解和实践指南

    一、MSBuild简介MSBuild是一种基于XML的构建引擎,用于在.NET Framework和.NET Core应用程序中自动化构建过程。它是Visual Studio的构建引擎,可在命令行或其他构建工具中使用
  • 得物效率前端微应用推进过程与思考

    一、背景效率工程随着业务的发展,组织规模的扩大,越来越多的企业开始意识到协作效率对于企业团队的重要性,甚至是决定其在某个行业竞争中突围的关键,是企业长久生存的根本。得物
  • 一文搞定Java NIO,以及各种奇葩流

    大家好,我是哪吒。很多朋友问我,如何才能学好IO流,对各种流的概念,云里雾里的,不求甚解。用到的时候,现百度,功能虽然实现了,但是为什么用这个?不知道。更别说效率问题了~下次再遇到,
  • 当家的盒马,加速谋生

    来源 | 价值星球Planet作者 | 归去来自己&ldquo;当家&rdquo;的盒马,开始加速谋生了。据盒马官微消息,盒马计划今年开放生鲜供应链,将其生鲜商品送往食堂。目前,盒马在上海已经与
  • 余承东:AI大模型技术的发展将会带来下一代智能终端操作系统的智慧体验

    8月4日消息,2023年华为开发者大会(HDC.Together)今天正式开幕,华为发布HarmonyOS 4、全新升级的鸿蒙开发套件、HarmonyOS Next开发者预览版本等一系列
  • 华为Mate 60保护壳曝光:硕大后置相机模组 凸起程度有惊喜

    这段时间以来,关于华为新旗舰的爆料日渐密集。据此前多方爆料,今年华为将开始恢复一年双旗舰战略,除上半年推出的P60系列外,往年下半年的Mate系列也将
Top