从Java并发集合看锁优化策略
2016-11-24 21:57
176 查看
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在读操作时可以进行无锁的并发,在写操作时才进行同步操作,在大量读少量写的场景下可以大大提高效率。
相关文章推荐
- JAVAWEB开发之Hibernate详解(三)——Hibernate的检索方式、抓取策略以及利用二级缓存进行优化、解决数据库事务并发问题
- JAVAWEB开发之Hibernate详解(三)——Hibernate的检索方式、抓取策略以及利用二级缓存进行优化、解决数据库事务并发问题
- 【Java高并发学习】JDK内部锁优化策略概要
- java也能写出点点算法-像C++一样去优化核心并发的代码例子1
- 探索并发编程(六)------Java多线程性能优化
- Java代码优化策略
- Java代码的优化策略
- java 并发集合
- Java多线程阻塞队列和并发集合
- Java性能优化的策略和常见方法
- 【Java】 Integer 包装器的比较小陷阱(一种优化策略惹得祸)
- Java优化策略(一):底层优化
- java性能优化策略
- 系统性能优化策略(JAVA)
- Java代码的优化策略
- hibernate之优化抓取(选择抓取策略之通过子查询预抓取集合)
- java.util.concurrent系列文章--(1)JDK1.5 并发集合
- Java程序性能优化总结--------数组/集合篇
- Visual C++优化对大型数据集合的并发访问
- Java性能优化的策略和常见方法