zoukankan      html  css  js  c++  java
  • Java 并发编程——CopyOnWriteArrayList

    1 简述

    CopyOnWriteArrayList 是从 JDK5 开始引进的并发集合之一,另一个是 CopyOnWriteArraySet,JDK 并没有提供 Map 的实现,我们之后将实现它。

    2 COW

    Copy-On-Write简称COW,是一种用于程序设计中的优化策略。思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略。这种策略使得我们可以并发的读,而不用获取全局锁(但是写则需要获取锁)。体现的是读写分离的思想。但是因为每次添加都会复制原有的数组内容,因此存在内存开销问题。相对的,其他 Concurrent* 类的读写都会获取锁。

    2.1 add 源码分析

     1     // 使用 volatile 类型,只通过   getArray/setArray 访问
     2     private transient volatile Object[] array;
     3 
     4    @Override
     5     public boolean add(E e) {
     6         // 获取锁
     7         final ReentrantLock lock = this.lock;
     8         lock.lock();
     9         try {
    10 
    11             Object[] elements = getArray();
    12             int len = elements.length;
    13             // 复制原有的数组
    14             Object[] newElements = Arrays.copyOf(elements, len + 1);
    15             newElements[len] = e;
    16             // 将原有数组指向新数组
    17             setArray(newElements);
    18             return true;
    19         } finally {
    20             lock.unlock();
    21         }
    22     }

    2.2 get 源码分析

    1     public E get(int index) {
    2         // 获取现数组,不需要加锁,所以可能会获取到旧的数据(当存在另一个线程对 List 进行写操作是)
    3         return get(getArray(), index);
    4     }

    根据 2.1 ,这个方法获取到的数组可能会是的。

    3 实现 CopyOnWriteMap 

    遵循上边的设计,我们可以围绕 COW 设计出 Map

      1 package cn.pancc.purejdk.concurrent.fenxi;
      2 
      3 import java.util.Collection;
      4 import java.util.HashMap;
      5 import java.util.Map;
      6 import java.util.Set;
      7 import java.util.concurrent.locks.ReentrantLock;
      8 
      9 /**
     10  * @author pancc
     11  * @version 1.0
     12  */
     13 public class CopyOnWriteMap<K, V> implements Map<K, V>, Cloneable, java.io.Serializable {
     14     private static final long serialVersionUID = -6907385757412808108L;
     15     private volatile Map<K, V> map = new HashMap<>();
     16 
     17     public Map<K, V> getMap() {
     18         return map;
     19     }
     20 
     21     public void setMap(Map<K, V> map) {
     22         this.map = map;
     23     }
     24 
     25     private final ReentrantLock lock = new ReentrantLock();
     26 
     27     @Override
     28     public int size() {
     29         return getMap().size();
     30     }
     31 
     32     @Override
     33     public boolean isEmpty() {
     34         return getMap().isEmpty();
     35     }
     36 
     37     @Override
     38     public boolean containsKey(Object key) {
     39         return getMap().containsKey(key);
     40     }
     41 
     42     @Override
     43     public boolean containsValue(Object value) {
     44         return getMap().containsValue(value);
     45     }
     46 
     47     @Override
     48     public V get(Object key) {
     49         return getMap().get(key);
     50     }
     51 
     52     @Override
     53     public V put(K key, V value) {
     54         lock.lock();
     55         try {
     56             Map<K, V> newMap = new HashMap<>(map);
     57             V v = newMap.put(key, value);
     58             this.map = newMap;
     59             return v;
     60         } finally {
     61             lock.unlock();
     62         }
     63     }
     64 
     65     @Override
     66     public V remove(Object key) {
     67         lock.lock();
     68         try {
     69             Map<K, V> newMap = new HashMap<>(map);
     70             V v = newMap.remove(key);
     71             this.map = newMap;
     72             return v;
     73         } finally {
     74             lock.unlock();
     75         }
     76     }
     77 
     78     @Override
     79     public void putAll(Map<? extends K, ? extends V> m) {
     80         lock.lock();
     81         try {
     82             Map<K, V> newMap = new HashMap<>(map);
     83             newMap.putAll(m);
     84             this.map = newMap;
     85         } finally {
     86             lock.unlock();
     87         }
     88     }
     89 
     90     @Override
     91     public void clear() {
     92         lock.lock();
     93         try {
     94             this.map = new HashMap<>();
     95         } finally {
     96             lock.unlock();
     97         }
     98     }
     99 
    100     @Override
    101     public Set<K> keySet() {
    102         return getMap().keySet();
    103     }
    104 
    105     @Override
    106     public Collection<V> values() {
    107         return getMap().values();
    108     }
    109 
    110     @Override
    111     public Set<Entry<K, V>> entrySet() {
    112         return getMap().entrySet();
    113     }
    114 }

    4 COW 的缺点

    • 内存占用问题:每次写操作都会执行复制操作
    • 数据一致性问题:写操作并不会及时影响到读操作获取的数据

    5 应用场景

    适用于读多写少的场景,如黑名单机制,单位信息缓存

  • 相关阅读:
    题解报告:hdu1995汉诺塔V(递推dp)
    黑色CSS3立体动画菜单
    jQuery计算器插件
    CSS3动画库animate.css
    缩略图悬浮效果的jQuery焦点图
    CSS伪元素实现的3D按钮
    CSS3 3D旋转按钮对话框
    jQuery仿Android锁屏图案应用
    jQuery横向图片手风琴
    jQuery滑动杆打分插件
  • 原文地址:https://www.cnblogs.com/siweipancc/p/12486599.html
Copyright © 2011-2022 走看看