从Java并发集合看锁优化策略
来源:互联网 发布:美工钢笔字 编辑:程序博客网 时间:2024/05/03 20:00
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在读操作时可以进行无锁的并发,在写操作时才进行同步操作,在大量读少量写的场景下可以大大提高效率。
1 0
- 从Java并发集合看锁优化策略
- 从JDK源码角度看并发锁的优化
- 【Java高并发学习】JDK内部锁优化策略概要
- 从JDK源码看Java并发特性
- java并发--并发集合
- 从Java看多核并发编程的2.0趋势
- 从JDK源码角度看java并发的公平性
- 从JDK源码角度看java并发线程的中断
- 从并发编程角度看Java内存模型
- 高并发性能优化策略
- 从蛋糕店看营销策略
- Java的并发策略
- 从集合的resize看Java HashMap的死循环
- 【并发编程】从Java内存模型看并发数据共享与线程安全
- Java并发容器并发集合
- 【Java并发编程】并发集合
- 从CMMI规范的角度看Java性能优化
- 从JVM的角度看JAVA代码--代码优化
- Hadoop集群环境的搭建
- Python对象的文档字符串(DocString):__doc__的写法和输出方法
- 组个最小数 (20)
- 使用Topshelf创建Windows服务
- redis
- 从Java并发集合看锁优化策略
- javascript中top、clientTop、scrollTop、offsetTop的讲解
- C语言问题(1)
- Java 多线程
- 新闻发布项目——访问温馨提示
- C语言中,malloc和free深入理解
- noip2016_day1_T1
- sockaddr和sockaddr_in详解
- Android ImageView用法