CopyOnWrite技术

copyOnWrite技术的思路是通过写时复制的方式来来解决并发的问题,采用一种读写分离的思想,这样在读的时候,可以并发读,提高效率。具体的方式,是并发读,然后写入前,先复制一份,然后在复制的那一份数据中,写入需要的数据,然后替换掉原来的引用,那么就写成功了。需要注意的是,copyOnWrite只能保证最终一致性,不能实时更新。

在介绍copyOnwrite技术前,先看下多线程集合的情况:

1.1、ArrayList的测试

public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                    list.add("a");
                }).start();
        }
        list.forEach(x->{
            System.out.print(x);
        });
  }

多运行几次,你可以得到有些数据为null的情况,比如: nullaaaaaaaaa   出现了线程安全问题

 

1.2、使用Vector类

   public static void main(String[] args) {
        List<String>  list = new Vector<>();
        for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                    list.add("a");
                }).start();
        }
        list.forEach(x->{
            System.out.print(x);
        });
    }

vector是一个比较古老的类,底层代码是直接加synchronized来解决并发问题的,性能比较低。源码:

// 底层代码,直接通过关键字synchronized来解决并发问题,但是性能比较低
public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
}

1.3、使用工具类Collections

使用工具类Collections的静态方法:synchronizedList,跟上述一样,线程安全,但是性能比较低

public static void main(String[] args) {
        List<String> list = Collections.synchronizedList(new ArrayList<>());
        for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                    list.add("a");
                }).start();
        }
        list.forEach(x->{
            System.out.print(x);
        });
    }

1.4、CopyOnWriteArrayList

适用于读多写比较少的场景

public static void main(String[] args) {
        List<String> list = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                    list.add("a");
                }).start();
        }
        list.forEach(x->{
            System.out.print(x);
        });
    }

查看底层源码:

public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        // 写入的时候加锁
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            // 复制一份副本newElements
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            // 往副本中写入数据
            newElements[len] = e;
            // 替换副本和原来数据的引用
            // array为旧数据的引用
            // final void setArray(Object[] a) {
            //     array = a; 
            // }
            //
            setArray(newElements); 
            return true;
        } finally {
            lock.unlock();
        }
    }

copyOnWrite的实现,内存会占用多一倍,因为复制一个副本,同时,这个时候别的线程使用这个list的话,用的还是旧的那个实例,所以这个不是实时的,有一定的时间延迟。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值