[关闭]
@22221cjp 2016-10-26T04:24:54.000000Z 字数 1934 阅读 1246

实现线程安全的一种方法:CopyOnWrite

技术


CopyOnWrite 顾名思义就是写时拷贝,具体过程是对容器进行操作的时候,先将容器拷贝一份(浅拷贝),然后对容器进行添加元素,删除等。最后将原来容器的引用改为新的容器。

本质是一种“读写分离”的思想。

JDK提供了两种CopyOnWrite容器:CopyOnWriteArrayList和CopyOnWriteArraySet

但是我们根据需要,也可以自己实现其他的容器的CopyOnWrite版本。比如CopyOnWriteMap,代码如下:

package com.charles.work;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 功能描述:  实现一个copy on write map,这是线程安全的,写时拷贝<p>
 *
 * @author : jinpeng.chen <p>
 * @version 1.0 2016-10-24
 * @since myworkspace 1.0
 */
public class CopyOnWriteMap<k, v> implements Map<k, v>, Cloneable {
    private volatile Map<k,v> internalMap;

    public CopyOnWriteMap() {
        this.internalMap = new HashMap<k, v>();
    }

    @Override
    public int size() {
        return internalMap.size();
    }

    @Override
    public boolean isEmpty() {
        return internalMap.isEmpty();
    }

    @Override
    public boolean containsKey(Object key) {
        return internalMap.containsKey(key);
    }

    @Override
    public boolean containsValue(Object value) {
        return internalMap.containsValue(value);
    }

    @Override
    public v get(Object key) {
        return internalMap.get(key);
    }

    @Override
    public v put(k key, v value) {
        synchronized (this) {
            Map<k, v> map = new HashMap<k, v>(internalMap);//copy
            v val = map.put(key, value);
            internalMap = map;
            return val;
        }
    }

    @Override
    public v remove(Object key) {
        synchronized (this) {
            Map<k, v> map = new HashMap<k, v>(internalMap);
            v remove = map.remove(key);
            internalMap = map;
            return remove;
        }
    }

    @Override
    public void putAll(Map<? extends k, ? extends v> m) {
        synchronized (this) {
            Map<k, v> map = new HashMap<k, v>(internalMap);
            map.putAll(m);
            internalMap=map;
        }
    }

    @Override
    public void clear() {
        synchronized (this) {
            internalMap = new HashMap<k, v>();
        }
    }

    @Override
    public Set<k> keySet() {
        return internalMap.keySet();
    }

    @Override
    public Collection<v> values() {
        return internalMap.values();
    }

    @Override
    public Set<Entry<k, v>> entrySet() {
        return internalMap.entrySet();
    }
}

需要注意:

  1. 减少扩容开销。根据实际需要,初始化CopyOnWriteMap的大小,避免写时CopyOnWriteMap扩容的开销。

  2. 使用批量添加。因为每次添加,容器每次都会进行复制,所以减少添加次数,可以减少容器的复制次数。

CopyOnWrite优点:
速度快,写的过程也不影响读

CopyOnWrite缺点:
读写不能实现实时一致性,但是保证最终一致性,如果要保证写完后立即能读到,不要用
每次写都需要拷贝,占用内存。且有性能消耗

试用场景:
读多写少的场景
尽量减少写操作,如果要写,也可以合并写操作,改为批量写

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注