从Java并发集合看锁优化策略
时间:2022-07-24
本文章向大家介绍从Java并发集合看锁优化策略,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
1.ConcurrentHashMap
ConcurrentHashMap是支持并发的HashMap类,可以在多线程环境下保证线程安全。ConcurrentHashMap的核心思想就是减小锁的粒度。传统的线程安全的Hashtable在同步时采用了synchronized关键字,所有对Hashtable的读写操作都要先获取对象锁,在锁竞争比较激烈的情况下会导致性能很低。ConcurrentHashMap在此基础上采用和分段的策略,将一个HashMap最多分为16个段(Segment),对不同段上的操作可以并发执行,只有在同一个段上的读写才使用加锁的策略。通过这种减小锁粒度的方式,大大提高了性能。如ConcurrentHashMap的put方法源码如下:
public V put(K key, V value) {
//先找到value所在的段
Segment<K,V> s;
if (value == null)
throw new NullPointerException();
int hash = hash(key);
int j = (hash >>> segmentShift) & segmentMask;
if ((s = (Segment<K,V>)UNSAFE.getObject // nonvolatile; recheck
(segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment
s = ensureSegment(j);
//针对对应的段进行操作
return s.put(key, hash, value, false);
}
ConcurrentHashMap.Segment的put方法如下:
final V put(K key, int hash, V value, boolean onlyIfAbsent) {
HashEntry<K,V> node = tryLock() ? null :
scanAndLockForPut(key, hash, value);
V oldValue;
try {
HashEntry<K,V>[] tab = table;
int index = (tab.length - 1) & hash;
HashEntry<K,V> first = entryAt(tab, index);
for (HashEntry<K,V> e = first;;) {
if (e != null) {
K k;
if ((k = e.key) == key ||
(e.hash == hash && key.equals(k))) {
oldValue = e.value;
if (!onlyIfAbsent) {
e.value = value;
++modCount;
}
break;
}
e = e.next;
}
else {
if (node != null)
node.setNext(first);
else
node = new HashEntry<K,V>(hash, key, value, first);
int c = count + 1;
if (c > threshold && tab.length < MAXIMUM_CAPACITY)
rehash(node);
else
setEntryAt(tab, index, node);
++modCount;
count = c;
oldValue = null;
break;
}
}
} finally {
unlock();
}
return oldValue;
}
可以看出,在对ConcurrentHashMap进行操作时,会先找到数据所在的段,只有在同一个段上的数据才会采用加锁的机制,非同段则可以并发执行。
2.CopyOnWriteArrayList
CopyOnWriteArrayList采用了读、写锁分离的思想。所有对CopyOnWriteArrayList的读操作可以进行无锁的并发执行,当进行写操作时,会先将原数组复制一份再进行修改,修改后将新数组的引用传递给原数组,并释放复制数组所占的空间。CopyOnWriteArrayList非常适合应用于大量读取少量修改的并发场景下。
CopyOnWriteArrayList的get方法如下:
public E get(int index) {
//直接进行随机访问
return get(getArray(), index);
}
add方法实现如下:
public boolean add(E e) {
final ReentrantLock lock = this.lock;
//加锁
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
//拷贝原数组
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
//将新数组的引用传递给原数组
setArray(newElements);
return true;
} finally {
//释放锁
lock.unlock();
}
}
综上,CopyOnWriteArrayList在读操作时可以进行无锁的并发,在写操作时才进行同步操作,在大量读少量写的场景下可以大大提高效率。
- 下载安装ActiveMQ(消息队列)
- springmvc框架开发中解决产生的乱码情况
- springmvc框架开发常用的注解总结
- 详谈Struts2
- 持久层框架之MyBatis
- 总结hibernate框架的常用检索方式
- 互联网项目架构之基于服务的分布式架构
- 会优化,你真的会优化吗?其实你可能真的缺少一份理解【数据库篇】
- 用户登录安全框架shiro—用户的认证和授权(一)
- 第一道防线__SpringMVC配置拦截器
- Web层框架对网站中所有异常的统一处理
- Spring MVC__自定义日期类型转换器
- 解决在控制层springmvc框架发出的400状态的错误
- 解决springmvc在单纯返回一个字符串对象时所出现的乱码情况(极速版)
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释