Java中Map实现线程安全的3种方式
作者:从哪里跌倒,就在哪里躺下 发布时间:2021-10-07 21:23:36
标签:Java,Map,线程安全
方式1. 使用Hashtable
Map<String,Object> hashtable=new Hashtable<String,Object>();
这是所有人最先想到的,那为什么它是线程安全的?那就看看它的源码,我们可以看出我们常用的put,get,containsKey等方法都是同步的,所以它是线程安全的
public synchronized boolean containsKey(Object key) {
? ? ? ? Entry<?,?> tab[] = table;
? ? ? ? int hash = key.hashCode();
? ? ? ? int index = (hash & 0x7FFFFFFF) % tab.length;
? ? ? ? for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
? ? ? ? ? ? if ((e.hash == hash) && e.key.equals(key)) {
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return false;
? ? }
?public synchronized V get(Object key) {
? ? ? ? Entry<?,?> tab[] = table;
? ? ? ? int hash = key.hashCode();
? ? ? ? int index = (hash & 0x7FFFFFFF) % tab.length;
? ? ? ? for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
? ? ? ? ? ? if ((e.hash == hash) && e.key.equals(key)) {
? ? ? ? ? ? ? ? return (V)e.value;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return null;
? ? }
? ? ?public synchronized V put(K key, V value) {
? ? ? ? // Make sure the value is not null
? ? ? ? if (value == null) {
? ? ? ? ? ? throw new NullPointerException();
? ? ? ? }
? ? ? ? // Makes sure the key is not already in the hashtable.
? ? ? ? Entry<?,?> tab[] = table;
? ? ? ? int hash = key.hashCode();
? ? ? ? int index = (hash & 0x7FFFFFFF) % tab.length;
? ? ? ? @SuppressWarnings("unchecked")
? ? ? ? Entry<K,V> entry = (Entry<K,V>)tab[index];
? ? ? ? for(; entry != null ; entry = entry.next) {
? ? ? ? ? ? if ((entry.hash == hash) && entry.key.equals(key)) {
? ? ? ? ? ? ? ? V old = entry.value;
? ? ? ? ? ? ? ? entry.value = value;
? ? ? ? ? ? ? ? return old;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? addEntry(hash, key, value, index);
? ? ? ? return null;
? ? }
其实现原理是在增删改查的方法上使用了synchronized锁机制,在多线程环境下,无论是读数据,还是修改数据,在同一时刻只能有一个线程在执行synchronize方法,因为是对整个表进行锁定。所以线程越多,对该map的竞争越激烈,效率越低,不推荐使用。
方式2. 使用Collections.synchronizedMap(new Hashtable())
其实现原理是使用工具类里面的静态方法,把传入进来的Hashtable包装成同步的,即在增删改查的方法上增加了synchronized所机制,其实现方式与Hashtable差不多,效率也差不多,不推荐使用。
Map map = Collections.synchronizedMap(new Hashtable());
以下是JDK源码
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
return new SynchronizedMap<>(m);
}
private static class SynchronizedMap<K,V>
implements Map<K,V>, Serializable {
private static final long serialVersionUID = 1978198479659022715L;
private final Map<K,V> m; // Backing Map
final Object mutex; // Object on which to synchronize
SynchronizedMap(Map<K,V> m) {
this.m = Objects.requireNonNull(m);
mutex = this;
}
SynchronizedMap(Map<K,V> m, Object mutex) {
this.m = m;
this.mutex = mutex;
}
public int size() {
synchronized (mutex) {return m.size();}
}
public boolean isEmpty() {
synchronized (mutex) {return m.isEmpty();}
}
public boolean containsKey(Object key) {
synchronized (mutex) {return m.containsKey(key);}
}
public boolean containsValue(Object value) {
synchronized (mutex) {return m.containsValue(value);}
}
public V get(Object key) {
synchronized (mutex) {return m.get(key);}
}
public V put(K key, V value) {
synchronized (mutex) {return m.put(key, value);}
}
public V remove(Object key) {
synchronized (mutex) {return m.remove(key);}
}
public void putAll(Map<? extends K, ? extends V> map) {
synchronized (mutex) {m.putAll(map);}
}
public void clear() {
synchronized (mutex) {m.clear();}
}
......
}
方式3. 使用ConcurrentHashMap
其实现原理是Hashtable是对整个表进行加锁,而ConcurrentHashMap是把表进行分段,初始情况下分成16段,每一段都有一把锁,当多个线程访问不同的段时,因为获取到的锁是不同的,所以可以并行的访问。效率比Hashtable高多了,推荐使用。
来源:https://blog.csdn.net/weixin_42812598/article/details/90708472


猜你喜欢
- using Word;下面的例子中包括C#对Word文档的创建、插入表格、设置样式等操作:(例子中代码有些涉及数据信息部分被省略,重要是介绍
- 前言此节假日为严格按照国家要求的双休和法定节假日并且包含节假日的补班信息,大家可根据自己的需求自定义处理哦。以下为Maven配置,是程序用到
- 本文以一个简单的实例来说明C#策略模式的实现方法,分享给大家供大家参考。具体实现方法如下:一般来说,当一个动作有多种实现方法,在实际使用时,
- 本文为大家分享了Android操作蓝牙2.0的使用方法,供大家参考,具体内容如下1.Android操作蓝牙2.0的使用流程(1)找到设备uu
- 本文给大家介绍Activity的生命周期,如果大家学习过iOS的小伙伴的话,Activity的生命周期和iOS中ViewController
- 前言本篇内容:提示语的国际化返回,自定义多语言。本文使用aop方式,拦截接口返回的数据,进行转换。正文 先看这次示例教
- 动态表单的含义是不要手动定义,直接在配置文件中进行定义。1.手动进行定义<form-beans > <form-bean
- 1.ArrayList 是基数组结构的,需要连续的内存空间从构造函数可以看出,ArrayList内部用一个Object数组来保存数据。对于无
- 序列化一般应用与以下场景之中:1.永久性保存对象,把对象通过序列化字节流保存到本地文件中;2.通过序列化在网络中传输对象3.通过序列化在进程
- 一、简介在实际的项目开发过程中,我们经常需要将某些变量从代码里面抽离出来,放在配置文件里面,以便更加统一、灵活的管理服务配置信息。比如,数据
- 正文 #方法一:使用string.Contains方法string.Contains是大小写敏感的,如果要用该方法来判断一个str
- 一直在使用Mybatis这个ORM框架,都是使用mybatis里的一些常用功能。今天在项目开发中有个业务是需要限制各个用户对某些表里的字段查
- spring.activemq.pool.enabled=false时,每发送一条数据都需要创建一个连接,这样会出现频繁创建和销毁连接的场景
- 本地异步处理,采用事件机制 可以使 代码解耦,更易读。事件机制实现模式是 观察者模式(或发布订阅模式),主要分为三部分:发布者、监听者、事件
- MyEclipse *的下载,找到MyEclipse的各种历史版本下载页面:http://www.myeclipsecn.com/简单说下,
- maven配置项目的jdk版本无效排查最近在配置项目的jdk的时候发现在pom.xml中配置的1.8版本无效,maven更新后就变成了1.7
- 听老师说,在以后的学习中大部分的异常都是空指针异常。所以抽点打游戏的时间来查询一下什么是空指针异常一:空指针异常产生的主要原因如下:(1)当
- Example官方介绍Query by Example (QBE) is a user-friendly querying techniqu
- 前言如今发短信功能已经成为互联网公司的标配,本篇文章将一步步实现java发送短信考察了许多提供短信服务的三方,几乎所有都需要企业认证才可以使
- Spring Data JPA查询方式及方法名查询规则Spring Data JPA通过解析方法名创建查询在执行查询时,Spring Dat