并发编码模式 - CopyOnWrite模式(COW)

本文详细介绍了Java并发编程中CopyOnWriteArrayList的使用场景、工作原理及其源码分析。CopyOnWriteArrayList适用于读多写少、数据量小且对一致性要求不高的情况。其在写操作时通过复制原数组并修改,然后替换引用,确保了读写的安全性。文章还给出了一个微服务中路由信息管理的实例,展示了CopyOnWriteArrayList在实际问题中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    解决线程处理共享数据除了之前的线程变量(ThreadLocal)和不可变(Immatable)模式外,还有一个方式就是CopyOnWrite模式(也叫COW ),但是有自己的适用场景。针对该模式 java juc提供了 CopyOnWriteArrayListCopyOnWriteArraySet(底层使用CopyOnWriteArrayList保证去重实现)。

一、使用场景

1、读多写少

2、数据量比较小

3、对数据的一致性要求不是非常的高

二、原理

    读数据:直接进行读取

    写数据:将原数据进行Copy,再进行修改(所以需要一致性要求数据量比较小),最后将原对象的属性指向修改后的数组地址;

所以当并行修改和查询时,可能查询到旧数据(所以需要一致性要求不是特别高

三、CopyOnWriteArrayList源码(其他方法与add类似)

public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
    private static final long serialVersionUID = 8673264195747942595L;
    final transient ReentrantLock lock = new ReentrantLock();
    private transient volatile Object[] array;
    private static final Unsafe UNSAFE;
    private static final long lockOffset;
}
public boolean add(E var1) {
    // 有修改时,先加锁(所以最好读多写少场景)
    ReentrantLock var2 = this.lock;
    var2.lock();

    boolean var6;
    try {
        Object[] var3 = this.getArray();
        int var4 = var3.length;
        // 先Copy再修改
        Object[] var5 = Arrays.copyOf(var3, var4 + 1);
        var5[var4] = var1;
        // 最后设置新值
        this.setArray(var5);
        var6 = true;
    } finally {
        var2.unlock();
    }
    return var6;
}

四、使用场景实例

    比如微服务去定时去获取服务请求列表信息时,如:Ribbon等服务列表,就比较适用该场景。数据一致性要求不是很高,数据量比较小,读多写少。

demo数据结构如: ConcurrentHashMap<String, CopyOnWriteArraySet<Router>>


//路由信息
public final class Router{
  private final String  ip;
  private final Integer port;
  private final String  iface;
  //构造函数
  public Router(String ip, 
      Integer port, String iface){
    this.ip = ip;
    this.port = port;
    this.iface = iface;
  }
  //重写equals方法
  public boolean equals(Object obj){
    if (obj instanceof Router) {
      Router r = (Router)obj;
      return iface.equals(r.iface) &&
             ip.equals(r.ip) &&
             port.equals(r.port);
    }
    return false;
  }
  public int hashCode() {
    //省略hashCode相关代码
  }
}
//路由表信息
public class RouterTable {
  //Key:接口名
  //Value:路由集合
  ConcurrentHashMap<String, CopyOnWriteArraySet<Router>> 
    rt = new ConcurrentHashMap<>();
  //根据接口名获取路由表
  public Set<Router> get(String iface){
    return rt.get(iface);
  }
  //删除路由
  public void remove(Router router) {
    Set<Router> set=rt.get(router.iface);
    if (set != null) {
      set.remove(router);
    }
  }
  //增加路由
  public void add(Router router) {
    Set<Router> set = rt.computeIfAbsent(
      route.iface, r -> 
        new CopyOnWriteArraySet<>());
    set.add(router);
  }
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值