Java读写锁,ReadWriteLock.java接口, RentrantReadWriteLock.java实现。通过读写锁,可以实现读-读线程并发,读-写,写-读线程互斥进行。以前面试遇到一个问题,ConcurrentHashMap的实现原理,如何封装Map效率更高。今天看了《Java并发编程实战》,封装的ReadWriteMap类,效率就比ConcurrentHashMap效率更高,在读多写少的场景。
ReadWriteMap.java
1 public class ReadWriteMap<K, V> { 2 private final Map<K, V> map; 3 private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); 4 private final Lock readLock = readWriteLock.readLock(); 5 private final Lock writeLock = readWriteLock.writeLock(); 6 7 public ReadWriteMap(Map<K, V> map){ 8 this.map = map; 9 } 10 11 public V put(K key, V value){ 12 writeLock.lock(); 13 try{ 14 return map.put(key, value); 15 } finally { 16 //释放锁,一定要写在finally里面 17 writeLock.unlock(); 18 } 19 } 20 21 public V get(K key){ 22 readLock.lock(); 23 try{ 24 return map.get(key); 25 } finally { 26 readLock.unlock(); 27 } 28 } 29 30 }
ConcurrentHashMap里面的putVal()方法
1 /** Implementation for put and putIfAbsent */ 2 final V putVal(K key, V value, boolean onlyIfAbsent) { 3 if (key == null || value == null) throw new NullPointerException(); 4 int hash = spread(key.hashCode()); 5 int binCount = 0; 6 for (Node<K,V>[] tab = table;;) { 7 Node<K,V> f; int n, i, fh; 8 if (tab == null || (n = tab.length) == 0) 9 tab = initTable(); 10 else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { 11 if (casTabAt(tab, i, null, 12 new Node<K,V>(hash, key, value, null))) 13 break; // no lock when adding to empty bin 14 } 15 else if ((fh = f.hash) == MOVED) 16 tab = helpTransfer(tab, f); 17 else { 18 V oldVal = null; 19 synchronized (f) { 20 if (tabAt(tab, i) == f) { 21 if (fh >= 0) { 22 binCount = 1; 23 for (Node<K,V> e = f;; ++binCount) { 24 K ek; 25 if (e.hash == hash && 26 ((ek = e.key) == key || 27 (ek != null && key.equals(ek)))) { 28 oldVal = e.val; 29 if (!onlyIfAbsent) 30 e.val = value; 31 break; 32 } 33 Node<K,V> pred = e; 34 if ((e = e.next) == null) { 35 pred.next = new Node<K,V>(hash, key, 36 value, null); 37 break; 38 } 39 } 40 } 41 else if (f instanceof TreeBin) { 42 Node<K,V> p; 43 binCount = 2; 44 if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, 45 value)) != null) { 46 oldVal = p.val; 47 if (!onlyIfAbsent) 48 p.val = value; 49 } 50 } 51 } 52 } 53 if (binCount != 0) { 54 if (binCount >= TREEIFY_THRESHOLD) 55 treeifyBin(tab, i); 56 if (oldVal != null) 57 return oldVal; 58 break; 59 } 60 } 61 } 62 addCount(1L, binCount); 63 return null; 64 }
使用的是synchronized进行同步,synchronized是独占锁,在读多写少的情况下效率不高,极端情况就是所有都是读线程,串行执行。