Copy-On-Write容器之二:CopyOnWriteArraySet

本文深入剖析了CopyOnWriteArraySet的实现原理,包括其数据结构、线程安全机制及核心方法。并通过示例展示了如何在并发环境中使用该集合。

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

一、CopyOnWriteArraySet简介

1. CopyOnWriteArraySet继承于AbstractSet,这就意味着它是一个集合。
2. CopyOnWriteArraySet包含CopyOnWriteArrayList对象,它是通过CopyOnWriteArrayList实现的。而CopyOnWriteArrayList本质是个动态数组队列,
所以CopyOnWriteArraySet相当于通过通过动态数组实现的“集合”! CopyOnWriteArrayList中允许有重复的元素;但是,CopyOnWriteArraySet是一个集合,所以它不能有重复集合。因此,CopyOnWriteArrayList额外提供了addIfAbsent()和addAllAbsent()这两个添加元素的API,通过这些API来添加元素时,只有当元素不存在时才执行添加操作!
至于CopyOnWriteArraySet的“线程安全”机制,和CopyOnWriteArrayList一样,是通过volatile和互斥锁来实现的。这个在前一章节介绍CopyOnWriteArrayList时数据结构时,已经进行了说明,这里就不再重复叙述了。

二、CopyOnWriteArraySet源码分析


2.1、类图结构

2.2、数据结构

2.3、CopyOnWriteArraySet中的lock

并发控制使用CopyOnWriteArrayList的ReentrantLock


2.4、成员变量

private final CopyOnWriteArrayList al;

2.5、构造函数

    public CopyOnWriteArraySet()
    {
        al = new CopyOnWriteArrayList();
    }

2.6、增加元素

    public boolean add(Object obj)
    {
        return al.addIfAbsent(obj);
    }

2.7、remove

    public boolean remove(Object obj)
    {
        return al.remove(obj);
    }

2.8、是否存在元素

    public boolean contains(Object obj)
    {
        return al.contains(obj);
    }

2.9、size

    public int size()
    {
        return al.size();
    }

2.10、clear

    public void clear()
    {
        al.clear();
    }

三、JDK或开源框架中使用

四、示例

package com.dxz.concurrent.cow;

import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetTest1 {

    // TODO: set是HashSet对象时,程序会出错。
    // private static Set<String> set = new HashSet<String>();
    private static Set<String> set = new CopyOnWriteArraySet<String>();

    public static void main(String[] args) {

        // 同时启动两个线程对set进行操作!
        new MyThread("ta").start();
        new MyThread("tb").start();
    }

    private static void printAll() {
        String value = null;
        Iterator iter = set.iterator();
        while (iter.hasNext()) {
            value = (String) iter.next();
            System.out.print(value + ", ");
        }
        System.out.println();
    }

    private static class MyThread extends Thread {
        MyThread(String name) {
            super(name);
        }

        @Override
        public void run() {
            int i = 0;
            while (i++ < 10) {
                // “线程名” + "-" + "序号"
                String val = Thread.currentThread().getName() + "-" + (i % 6);
                set.add(val);
                // 通过“Iterator”遍历set。
                printAll();
            }
        }
    }
}

结果:

ta-1, tb-1, 
ta-1, tb-1, 
ta-1, tb-1, ta-1, tb-1, ta-2, 
ta-1, tb-1, ta-2, ta-2, tb-2, 
ta-1, tb-1, ta-2, tb-2, ta-3, tb-3, 
ta-1, tb-1, ta-2, tb-2, ta-3, tb-3, tb-4, 
ta-1, tb-1, ta-2, tb-2, ta-3, tb-3, tb-4, tb-5, 
ta-1, tb-1, ta-2, tb-2, ta-3, tb-3, tb-4, tb-5, tb-0, 
ta-1, tb-1, ta-2, tb-2, ta-3, tb-3, tb-4, tb-5, tb-0, 
ta-1, tb-1, ta-2, tb-2, ta-3, tb-3, tb-4, tb-5, tb-0, 
ta-1, tb-1, ta-2, tb-2, ta-3, tb-3, tb-4, tb-5, tb-0, 
ta-1, tb-1, ta-2, tb-2, ta-3, tb-2, ta-3, 
ta-1, tb-1, ta-2, tb-2, ta-3, tb-3, tb-4, tb-5, tb-0, ta-4, 
ta-1, tb-1, ta-2, tb-2, ta-3, tb-3, tb-4, tb-5, tb-0, ta-4, ta-5, 
ta-1, tb-1, ta-2, tb-2, ta-3, tb-3, tb-3, tb-4, tb-5, tb-0, 
tb-4, tb-5, tb-0, ta-4, ta-5, ta-0, 
ta-1, tb-1, ta-2, tb-2, ta-3, tb-3, tb-4, tb-5, tb-0, ta-4, ta-5, ta-0, 
ta-1, tb-1, ta-2, tb-2, ta-3, tb-3, tb-4, tb-5, tb-0, ta-4, ta-5, ta-0, 
ta-1, tb-1, ta-2, tb-2, ta-3, tb-3, tb-4, tb-5, tb-0, ta-4, ta-5, ta-0, 
ta-1, tb-1, ta-2, tb-2, ta-3, tb-3, tb-4, tb-5, tb-0, ta-4, ta-5, ta-0, 

 

Java 提供了丰富的并发集合类,它们旨在支持多线程环境下的高效操作。这些类位于 `java.util.concurrent` 包及其子包中,并通过内置锁、原子变量和其他同步机制确保数据的一致性和安全性。 ### 常见的 Java 并发集合类 #### 1. **ConcurrentHashMap** - 这是一个高度优化的哈希表实现,在高并发环境下性能优于传统的 `synchronized HashMap` 或 `Collections.synchronizedMap()`。 - 支持高效的读取和更新操作,允许同时进行多次只读访问以及有限次数的写入操作。 #### 2. **CopyOnWriteArrayList** - 它是一种线程安全的变长数组实现。它的核心思想是在每次修改时创建整个列表的新副本,因此适合用于读多写少的场景。 - 写操作代价较高,但读操作无需加锁,非常快。 #### 3. **CopyOnWriteArraySet** - 相当于基于 `CopyOnWriteArrayList` 实现的一个线程安全的 Set 集合,内部使用一个不可修改的 List 来存储元素。 #### 4. **BlockingQueue 接口及其实现类** - 设计目标是为了解决生产者消费者模型的问题。它提供了一个阻塞队列的功能,即在需要的时候会自动等待资源可用后再继续处理任务。 - **LinkedBlockingQueue**: 双端链式队列,默认容量无限大; - **ArrayBlockingQueue**: 固定大小的有界循环缓冲区; - **PriorityBlockingQueue**: 具备优先级顺序的支持版本(非公平排序); - **SynchronousQueue**: 没有任何内部存储空间,每一个插入动作都必须有一个移除动作相匹配; #### 5. **ConcurrentSkipListMap 和 ConcurrentSkipListSet** - 分别对应有序映射结构和无序唯一值集合的数据类型。底层采用跳表算法保证良好的查找效率的同时也具备较好的并行能力。 #### 6. **Atomic 类族** - 虽然严格来说不是“集合”,但是提供了许多针对基本类型的原子级别操作功能,比如自增等基础算术运算。 - AtomicBoolean / AtomicInteger / LongAdder 等... --- ### 使用注意事项 - 根据实际需求选择合适的容器类别非常重要。例如如果只是简单地共享状态,则考虑用简单的 atomic variables 即可减少开销; - 对于频繁改动的数据集应避免 copy-on-write 方案以免带来过高的内存负担;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值