CopyOnWriteArrayList

CopyOnWriteArrayList

在这里插入图片描述
在这里插入图片描述
CopyOnWriteArrayList诞生记
在这里插入图片描述
在这里插入图片描述
适用场景
在这里插入图片描述
在这里插入图片描述
CopyOnWriteArrayList:就是不能一起写,可以一边读一边写,也可以一边写一边读。从这个方面来说,比读写锁强,读写锁是可以多读一写。
代码演示

package copyonwrite;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * 描述: 演示CopyOnWriteArrayList可以在迭代过程中修改数组内容,但是ArrayList不行,对比
 */
public class CopyOnWriteArrayListDemo1 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        list.add("5");
        Iterator<String> iterator = list.iterator();

        while (iterator.hasNext()){
            System.out.println("list is" + list);
            String next = iterator.next();
            System.out.println(next);

            if (next.equals("2")){
                list.remove("5");
            }
            if (next.equals("3")){
                list.add("3 found");
            }
        }
    }
}

在这里插入图片描述
用ArrayList迭代过程中,修改会报错;
当改为CopyOnWriteArrayList,其他都不变的情况下

package copyonwrite;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 描述: 演示CopyOnWriteArrayList可以在迭代过程中(读)修改数组内容,但是ArrayList不行,对比
 */
public class CopyOnWriteArrayListDemo1 {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        list.add("5");
        Iterator<String> iterator = list.iterator();

        while (iterator.hasNext()){
            System.out.println("list is" + list);
            String next = iterator.next();
            System.out.println(next);

            if (next.equals("2")){
                list.remove("5");
            }
            if (next.equals("3")){
                list.add("3 found");
            }
        }
    }
}

结果如下:
在这里插入图片描述
这时候,可以看到CopyOnWriteArrayList的特性,就是你管你的修改,我管我的迭代。我还是拿着我之前没改过的内容来进行迭代。
CopyOnWrite:
在计算机中,当要修改内存时,有一种机制。就是,我先复制一份内存,复制原内存中的东西。然后,再进行修改。然后,指向原来那个内存的指针,指向新的内存。这样,原来那块内存的指针就可以被回收了。
CopyOnWrite:就是这个这个机制,它在写的时候,去Copy一份出来,然后,在新的内存经常操作,全部搞定以后,再把容易的应用指向新的内存中。这时候的好处,就是在读的时候,不会有干扰。
在这里插入图片描述

不可变原理指的是在CopyOnWriteArrayList中,每次该的时候,就会创建一个新的副本,对于旧的副本来说就是不可变的,所以,不管有多少线程并发去读它,它都是安全的。
在迭代的过程中,该数据CopyOnWriteArrayList不会报错,而ArrayList则会报错。
ArrayList报错原因分析:
在迭代过程中,会先检测 checkForComodification();
在这里插入图片描述
下面进入到checkForComodification()进行查看
在这里插入图片描述
这里面有modCount 和 expectedModCount这两个参数,其中,modCount代表的是改变的次数,expectedModCount代表的是希望改变的次数。
在这里插入图片描述
在我们新建迭代器的时候,我们会把当前的modCount给存下来。
所以,在你用迭代器进行迭代的时候,如果对modCount 进行更改,就会抛出ConcurrentModificationException异常了。
但是,CopyOnWriteArrayList不会抛出异常。但是,他有一个问题,它的数据可能是过期的。

package copyonwrite;

import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 *  描述:  对比两个迭代器
 */
public class CopyOnWriteArrayListDemo2 {
    public static void main(String[] args) {
        CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>( new Integer[]{1,2,3});
        System.out.println(list);
        // 它所能拿到的数据取决于它的诞生时间,而不是它的迭代时间
        Iterator<Integer> itr1 = list.iterator();

        list.add(4);
        System.out.println(list);
        Iterator<Integer> itr2 = list.iterator();
        itr1.forEachRemaining(System.out::println);
        itr2.forEachRemaining(System.out::println);

    }
}

结果如下:
在这里插入图片描述
结论:它所能拿到的数据取决于它的诞生时间,而不是它的迭代时间。
在这里插入图片描述
在这里插入图片描述
首先,要去查看一下CopyOnWriteArrayList的数据结构,主要看的是锁。
在这里插入图片描述
发现锁为ReentrantLock
然后去看add方法
在这里插入图片描述
其源码如下:先进行加锁,然后复制一份新的数组,然后把add这个加进去。然后,再让原来的指针去指向它。再进行解锁。所以,从时间复杂度来看,CopyOnWrite系列的集合,都不适合进行添加,比较时间复杂度太高了。
下面在进行查看get方法
在这里插入图片描述
在这里插入图片描述
可以发现他是没有锁的。很显然,这就效率很快。但是,可能导致更新不及时的问题。
可能你添加元素时,它还没有让指针指向新的数组,但是,你调用get去查了。可能查不到。但是,他速度还是很快的。应该发生的概率不大。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值