当前位置:   article > 正文

Java并发集合之CopyOnWriteArraySet使用与原理_java copyonwritearrayset

java copyonwritearrayset

CopyOnWriteArraySet 简介

CopyOnWriteArraySet是线程安全的Set集合,相当于线程安全的HashSet。
注意:HashSet的实现是通过散列表HashMap实现的,但是CopyOnWriteArraySet是通过动态数组CopyOnWriteArrayList实现的

CopyOnWriteArraySet 的特性

  • 适用于数据量较小且读多写少的场景
  • 它是线程安全的
  • 新增和删除等修改数据的操作开销很大,涉及到数组复制后续源码解析会详解
  • 迭代器只支持读取不支持变更,并且在迭代过程中其他线程写入集合不会发生并发冲突
  • 迭代器的数据来源于迭代时的快照数据

CopyOnWriteArraySet的数据结构

CopyOnWriteArraySet的底层数据结构是CopyOnWriteArrayList实现的线程安全的可变数组

public class CopyOnWriteArraySet<E> extends AbstractSet<E>
        implements java.io.Serializable {
    private static final long serialVersionUID = 5457747651344034263L;

    private final CopyOnWriteArrayList<E> al;
  • 1
  • 2
  • 3
  • 4
  • 5

CopyOnWriteArraySet的部分源码解析

构造方法

  • 无参构造方法,构造一个空的CopyOnWriteArrayList
public CopyOnWriteArraySet() {
        al = new CopyOnWriteArrayList<E>();
    }
  • 1
  • 2
  • 3
  • 通过Collection构造
public CopyOnWriteArraySet(Collection<? extends E> c) {
		// 如果是CopyOnWriteArraySet类型,则获取到底层的CopyOnWriteArrayList对象创建新的CopyOnWriteArrayList对象
        if (c.getClass() == CopyOnWriteArraySet.class) {
            @SuppressWarnings("unchecked") CopyOnWriteArraySet<E> cc =
                (CopyOnWriteArraySet<E>)c;
            al = new CopyOnWriteArrayList<E>(cc.al);
        }
        else {
            al = new CopyOnWriteArrayList<E>();
            al.addAllAbsent(c);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

变更数据方法

  • add方法,直接调用CopyOnWriteArrayList的addIfAbsent方法实现不重复的插入数据
public boolean add(E e) {
        return al.addIfAbsent(e);
    }
  • 1
  • 2
  • 3
  • remove方法,直接调用CopyOnWriteArrayList的remove方法实现删除数据
public boolean remove(Object o) {
        return al.remove(o);
    }
  • 1
  • 2
  • 3

CopyOnWriteArraySet变更数据总结:
CopyOnWriteArraySet完全依赖于内部的CopyOnWriteArrayList的方法来实现,逻辑也很简单,具体逻辑可以参考上一篇的CopyOnWriteArrayList的文章

迭代器方法

  • iterator方法,同样也是直接调用CopyOnWriteArrayList的迭代器方法
public Iterator<E> iterator() {
        return al.iterator();
    }
  • 1
  • 2
  • 3

一个实例对比CopyOnWriteArraySet和HashSet

  • 公共类
private static void printAll(Set<String> set) {
        System.out.println(set);
    }

    static class SetRunnable implements Runnable {

        private final Set<String> set;

        SetRunnable(Set<String> set) {
            this.set = set;
        }

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                set.add(Thread.currentThread().getName() + "-" + i);
                printAll(set);
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 多线程操作HashSet
@Test
    public void notUseJuc() throws InterruptedException {
        Set<String> set = new HashSet<>();
        final Thread th1 = new Thread(new SetRunnable(set));
        final Thread th2 = new Thread(new SetRunnable(set));

        th1.start();
        th2.start();
        th2.join();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

执行过程中有概率报错:

D:\mysoft\jdk-8u271\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\mysoft\JetBrains\IntelliJ IDEA 2022.2.3\lib\idea_rt.jar=56700:D:\mysoft\JetBrains\IntelliJ IDEA 2022.2.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\mysoft\JetBrains\IntelliJ IDEA 2022.2.3\lib\idea_rt.jar;D:\mysoft\JetBrains\IntelliJ IDEA 2022.2.3\plugins\junit\lib\junit5-rt.jar;D:\mysoft\JetBrains\IntelliJ IDEA 2022.2.3\plugins\junit\lib\junit-rt.jar;D:\mysoft\jdk-8u271\jre\lib\charsets.jar;D:\mysoft\jdk-8u271\jre\lib\deploy.jar;D:\mysoft\jdk-8u271\jre\lib\ext\access-bridge-64.jar;D:\mysoft\jdk-8u271\jre\lib\ext\cldrdata.jar;D:\mysoft\jdk-8u271\jre\lib\ext\dnsns.jar;D:\mysoft\jdk-8u271\jre\lib\ext\jaccess.jar;D:\mysoft\jdk-8u271\jre\lib\ext\jfxrt.jar;D:\mysoft\jdk-8u271\jre\lib\ext\localedata.jar;D:\mysoft\jdk-8u271\jre\lib\ext\nashorn.jar;D:\mysoft\jdk-8u271\jre\lib\ext\sunec.jar;D:\mysoft\jdk-8u271\jre\lib\ext\sunjce_provider.jar;D:\mysoft\jdk-8u271\jre\lib\ext\sunmscapi.jar;D:\mysoft\jdk-8u271\jre\lib\ext\sunpkcs11.jar;D:\mysoft\jdk-8u271\jre\lib\ext\zipfs.jar;D:\mysoft\jdk-8u271\jre\lib\javaws.jar;D:\mysoft\jdk-8u271\jre\lib\jce.jar;D:\mysoft\jdk-8u271\jre\lib\jfr.jar;D:\mysoft\jdk-8u271\jre\lib\jfxswt.jar;D:\mysoft\jdk-8u271\jre\lib\jsse.jar;D:\mysoft\jdk-8u271\jre\lib\management-agent.jar;D:\mysoft\jdk-8u271\jre\lib\plugin.jar;D:\mysoft\jdk-8u271\jre\lib\resources.jar;D:\mysoft\jdk-8u271\jre\lib\rt.jar;D:\workspace\myself\mycsdn-demo\target\test-classes;D:\mavenRepository\junit\junit\4.13.2\junit-4.13.2.jar;D:\mavenRepository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.bufan.juc.JucSetTest,notUseJuc
[Thread-0-0, Thread-1-0]
[Thread-1-1, Thread-0-0, Thread-1-0]
[Thread-1-1, Thread-1-2, Thread-0-0, Thread-1-0]
[Thread-1-3, Thread-1-1, Thread-1-2, Thread-0-0, Thread-1-0]
[Thread-1-3, Thread-1-4, Thread-1-1, Thread-1-2, Thread-0-0, Thread-1-0]
[Thread-1-5, Thread-1-3, Thread-1-4, Thread-1-1, Thread-1-2, Thread-0-0, Thread-1-0]
[Thread-1-5, Thread-1-6, Thread-1-3, Thread-1-4, Thread-1-1, Thread-1-2, Thread-0-0, Thread-1-0]
[Thread-1-7, Thread-1-5, Thread-1-6, Thread-1-3, Thread-1-4, Thread-1-1, Thread-1-2, Thread-0-0, Thread-1-0]
[Thread-1-7, Thread-1-8, Thread-1-5, Thread-1-6, Thread-1-3, Thread-1-4, Thread-1-1, Thread-1-2, Thread-0-0, Thread-1-0]
[Thread-1-9, Thread-1-7, Thread-1-8, Thread-1-5, Thread-1-6, Thread-1-3, Thread-1-4, Thread-1-1, Thread-1-2, Thread-0-0, Thread-1-0]
Exception in thread "Thread-0" java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextNode(HashMap.java:1445)
	at java.util.HashMap$KeyIterator.next(HashMap.java:1469)
	at java.util.AbstractCollection.toString(AbstractCollection.java:461)
	at java.lang.String.valueOf(String.java:2994)
	at java.io.PrintStream.println(PrintStream.java:821)
	at com.bufan.juc.JucSetTest.printAll(JucSetTest.java:40)
	at com.bufan.juc.JucSetTest.access$000(JucSetTest.java:15)
	at com.bufan.juc.JucSetTest$SetRunnable.run(JucSetTest.java:55)
	at java.lang.Thread.run(Thread.java:748)

Process finished with exit code 0

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 多线程操作CopyOnWriteArraySet
@Test
    public void useJuc() throws InterruptedException {
        Set<String> list = new CopyOnWriteArraySet<>();
        final Thread th1 = new Thread(new SetRunnable(list));
        final Thread th2 = new Thread(new SetRunnable(list));

        th1.start();
        th2.start();
        th2.join();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

执行过程不会报并发异常

D:\mysoft\jdk-8u271\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\mysoft\JetBrains\IntelliJ IDEA 2022.2.3\lib\idea_rt.jar=56769:D:\mysoft\JetBrains\IntelliJ IDEA 2022.2.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\mysoft\JetBrains\IntelliJ IDEA 2022.2.3\lib\idea_rt.jar;D:\mysoft\JetBrains\IntelliJ IDEA 2022.2.3\plugins\junit\lib\junit5-rt.jar;D:\mysoft\JetBrains\IntelliJ IDEA 2022.2.3\plugins\junit\lib\junit-rt.jar;D:\mysoft\jdk-8u271\jre\lib\charsets.jar;D:\mysoft\jdk-8u271\jre\lib\deploy.jar;D:\mysoft\jdk-8u271\jre\lib\ext\access-bridge-64.jar;D:\mysoft\jdk-8u271\jre\lib\ext\cldrdata.jar;D:\mysoft\jdk-8u271\jre\lib\ext\dnsns.jar;D:\mysoft\jdk-8u271\jre\lib\ext\jaccess.jar;D:\mysoft\jdk-8u271\jre\lib\ext\jfxrt.jar;D:\mysoft\jdk-8u271\jre\lib\ext\localedata.jar;D:\mysoft\jdk-8u271\jre\lib\ext\nashorn.jar;D:\mysoft\jdk-8u271\jre\lib\ext\sunec.jar;D:\mysoft\jdk-8u271\jre\lib\ext\sunjce_provider.jar;D:\mysoft\jdk-8u271\jre\lib\ext\sunmscapi.jar;D:\mysoft\jdk-8u271\jre\lib\ext\sunpkcs11.jar;D:\mysoft\jdk-8u271\jre\lib\ext\zipfs.jar;D:\mysoft\jdk-8u271\jre\lib\javaws.jar;D:\mysoft\jdk-8u271\jre\lib\jce.jar;D:\mysoft\jdk-8u271\jre\lib\jfr.jar;D:\mysoft\jdk-8u271\jre\lib\jfxswt.jar;D:\mysoft\jdk-8u271\jre\lib\jsse.jar;D:\mysoft\jdk-8u271\jre\lib\management-agent.jar;D:\mysoft\jdk-8u271\jre\lib\plugin.jar;D:\mysoft\jdk-8u271\jre\lib\resources.jar;D:\mysoft\jdk-8u271\jre\lib\rt.jar;D:\workspace\myself\mycsdn-demo\target\test-classes;D:\mavenRepository\junit\junit\4.13.2\junit-4.13.2.jar;D:\mavenRepository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.bufan.juc.JucSetTest,useJuc
[Thread-0-0, Thread-1-0]
[Thread-0-0, Thread-1-0]
[Thread-0-0, Thread-1-0, Thread-0-1]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2, Thread-1-2]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2, Thread-1-2, Thread-0-3]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2, Thread-1-2, Thread-0-3, Thread-1-3]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2, Thread-1-2, Thread-0-3, Thread-1-3, Thread-0-4]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2, Thread-1-2, Thread-0-3, Thread-1-3, Thread-0-4, Thread-1-4]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2, Thread-1-2, Thread-0-3, Thread-1-3, Thread-0-4, Thread-1-4, Thread-0-5]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2, Thread-1-2, Thread-0-3, Thread-1-3, Thread-0-4, Thread-1-4, Thread-0-5, Thread-1-5]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2, Thread-1-2, Thread-0-3, Thread-1-3, Thread-0-4, Thread-1-4, Thread-0-5, Thread-1-5, Thread-0-6]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2, Thread-1-2, Thread-0-3, Thread-1-3, Thread-0-4, Thread-1-4, Thread-0-5, Thread-1-5, Thread-0-6, Thread-1-6]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2, Thread-1-2, Thread-0-3, Thread-1-3, Thread-0-4, Thread-1-4, Thread-0-5, Thread-1-5, Thread-0-6, Thread-1-6, Thread-0-7]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2, Thread-1-2, Thread-0-3, Thread-1-3, Thread-0-4, Thread-1-4, Thread-0-5, Thread-1-5, Thread-0-6, Thread-1-6, Thread-0-7, Thread-1-7]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2, Thread-1-2, Thread-0-3, Thread-1-3, Thread-0-4, Thread-1-4, Thread-0-5, Thread-1-5, Thread-0-6, Thread-1-6, Thread-0-7, Thread-1-7, Thread-0-8]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2, Thread-1-2, Thread-0-3, Thread-1-3, Thread-0-4, Thread-1-4, Thread-0-5, Thread-1-5, Thread-0-6, Thread-1-6, Thread-0-7, Thread-1-7, Thread-0-8, Thread-1-8]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2, Thread-1-2, Thread-0-3, Thread-1-3, Thread-0-4, Thread-1-4, Thread-0-5, Thread-1-5, Thread-0-6, Thread-1-6, Thread-0-7, Thread-1-7, Thread-0-8, Thread-1-8, Thread-0-9]
[Thread-0-0, Thread-1-0, Thread-0-1, Thread-1-1, Thread-0-2, Thread-1-2, Thread-0-3, Thread-1-3, Thread-0-4, Thread-1-4, Thread-0-5, Thread-1-5, Thread-0-6, Thread-1-6, Thread-0-7, Thread-1-7, Thread-0-8, Thread-1-8, Thread-0-9, Thread-1-9]

Process finished with exit code 0

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/821946
推荐阅读
相关标签
  

闽ICP备14008679号