CopyOnWriteArraySet:线程安全解析

📕我是廖志伟,一名Java开发工程师、《Java项目实战——深入理解大型互联网企业通用技术》(基础篇)(进阶篇)、(架构篇)、《解密程序员的思维密码——沟通、演讲、思考的实践》作者、清华大学出版社签约作家、Java领域优质创作者、CSDN博客专家、阿里云专家博主、51CTO专家博主、产品软文专业写手、技术文章评审老师、技术类问卷调查设计师、幕后大佬社区创始人、开源项目贡献者。

📘拥有多年一线研发和团队管理经验,研究过主流框架的底层源码(Spring、SpringBoot、SpringMVC、SpringCloud、Mybatis、Dubbo、Zookeeper),消息中间件底层架构原理(RabbitMQ、RocketMQ、Kafka)、Redis缓存、MySQL关系型数据库、 ElasticSearch全文搜索、MongoDB非关系型数据库、Apache ShardingSphere分库分表读写分离、设计模式、领域驱动DDD、Kubernetes容器编排等。

📙不定期分享高并发、高可用、高性能、微服务、分布式、海量数据、性能调优、云原生、项目管理、产品思维、技术选型、架构设计、求职面试、副业思维、个人成长等内容。

Java程序员廖志伟

💡在这个美好的时刻,笔者不再啰嗦废话,现在毫不拖延地进入文章所要讨论的主题。接下来,我将为大家呈现正文内容。

CSDN

🍊 并发编程核心知识点之CopyOnWriteArraySet:概述

在多线程环境下,尤其是在高并发场景中,数据结构的线程安全性成为了一个关键问题。想象一个在线购物平台,当用户同时进行商品搜索、添加购物车和结算操作时,如果数据结构处理不当,可能会导致数据不一致或竞态条件。为了解决这类问题,CopyOnWriteArraySet作为一种线程安全的集合实现,被广泛应用于需要高并发读操作而写操作相对较少的场景。

CopyOnWriteArraySet之所以重要,是因为它提供了一种在并发环境下保证集合元素安全访问和修改的机制。在传统的线程安全集合中,如使用synchronized关键字或ReentrantReadWriteLock,写操作通常需要锁定整个集合,这会导致读操作在写操作期间被阻塞,从而降低系统的整体性能。而CopyOnWriteArraySet通过在每次修改操作时创建集合的一个新副本,从而避免了这种性能损失。

接下来,我们将深入探讨CopyOnWriteArraySet的概念,包括其工作原理和实现细节;分析其在实际应用中的场景,如缓存系统、日志管理等;并讨论其优势与劣势,以便读者能够全面了解这一并发编程核心知识点。

在接下来的内容中,我们将首先介绍CopyOnWriteArraySet的概念,解释其如何通过写时复制(Copy-On-Write)策略来保证线程安全。随后,我们将探讨CopyOnWriteArraySet在实际开发中的应用场景,并举例说明其如何解决特定的问题。最后,我们将分析CopyOnWriteArraySet的优势和劣势,帮助读者在需要时做出合理的选择。

CopyOnWriteArraySet 概念

CopyOnWriteArraySet 是 Java 集合框架中的一种线程安全的集合实现,它基于数组来实现。与传统的线程安全集合如 synchronizedList 或 ReentrantLockList 相比,CopyOnWriteArraySet 在写操作时不会阻塞读操作,因此适用于读多写少的并发场景。

🎉 实现原理

CopyOnWriteArraySet 的核心思想是“写时复制”,即每次修改操作(如 add、remove、set)都会创建一个新的数组,并将修改后的元素复制到新数组中。这样,读操作始终在原始数组上进行,保证了读操作的原子性和线程安全性。

以下是 CopyOnWriteArraySet 的基本实现原理:

  1. 初始化:CopyOnWriteArraySet 初始化时,会创建一个空数组。
  2. 读操作:当进行读操作时(如 get、contains),直接在原始数组上进行,无需加锁。
  3. 写操作:当进行写操作时,首先获取当前数组的长度,然后创建一个新的数组,长度与原数组相同。接着,将原数组中的元素复制到新数组中,并对新数组进行修改。最后,将新数组赋值给内部变量,完成写操作。

🎉 适用场景

CopyOnWriteArraySet 适用于以下场景:

  • 读多写少:当集合中的读操作远多于写操作时,CopyOnWriteArraySet 可以提供更高的并发性能。
  • 数据量小:由于每次写操作都会创建一个新的数组,因此 CopyOnWriteArraySet 不适用于数据量大的场景。
  • 读操作复杂:当读操作需要遍历整个集合时,CopyOnWriteArraySet 可以提供更好的性能。

🎉 性能特点

CopyOnWriteArraySet 的性能特点如下:

特点说明
读操作高性能,无需加锁
写操作低性能,每次写操作都会创建一个新的数组
线程安全线程安全,无需额外同步措施

🎉 与其他集合类的比较

集合类优点缺点
CopyOnWriteArraySet读操作高性能,线程安全写操作低性能,不适用于数据量大或写操作频繁的场景
synchronizedList线程安全,写操作高性能读操作性能较差,需要加锁
ReentrantLockList线程安全,读写操作性能较好需要手动管理锁,代码复杂

🎉 线程安全机制

CopyOnWriteArraySet 的线程安全机制主要依赖于以下两点:

  1. 读操作:读操作直接在原始数组上进行,无需加锁。
  2. 写操作:写操作通过创建新的数组并复制元素来实现,保证了写操作的原子性。

🎉 使用注意事项

使用 CopyOnWriteArraySet 时,需要注意以下事项:

  • 读多写少:确保读操作远多于写操作,否则性能会受到影响。
  • 数据量小:避免在数据量大的场景中使用 CopyOnWriteArraySet。
  • 读操作复杂:当读操作需要遍历整个集合时,考虑使用其他线程安全的集合类。

🎉 与读写锁的比较

特点CopyOnWriteArraySet读写锁
读操作高性能,无需加锁高性能,无需加锁
写操作低性能,每次写操作都会创建一个新的数组高性能,读写分离
线程安全线程安全,无需额外同步措施线程安全,需要手动管理锁

🎉 在并发编程中的应用案例

以下是一个使用 CopyOnWriteArraySet 的并发编程应用案例:

import java.util.concurrent.CopyOnWriteArraySet;

public class ConcurrentExample {
    private static final CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();

    public static void main(String[] args) {
        // 模拟读操作
        for (int i = 0; i < 1000; i++) {
            set.add("Element " + i);
        }

        // 模拟写操作
        for (int i = 0; i < 1000; i++) {
            set.remove("Element " + i);
        }
    }
}

在这个案例中,CopyOnWriteArraySet 在读操作和写操作中均表现出良好的性能。

CopyOnWriteArraySet 是 Java 并发集合框架中的一个重要成员,它基于 CopyOnWriteArrayList 实现,适用于读多写少的并发场景。下面,我将从应用场景这个维度,详细阐述 CopyOnWriteArraySet 的特点。

🎉 应用场景

CopyOnWriteArraySet 适用于以下几种场景:

📝 1. 需要保证数据一致性的场景

在多线程环境下,CopyOnWriteArraySet 可以保证每次读取数据时,都是最新的数据。这是因为每次修改操作(如添加、删除元素)都会创建一个新的数组,并将修改后的数据写入新数组中。这样,即使多个线程同时进行修改操作,也不会相互影响,从而保证了数据的一致性。

📝 2. 读多写少的场景

由于 CopyOnWriteArraySet 的修改操作需要创建新的数组,因此它的写性能较低。但是,在读多写少的场景下,这种性能损失是可以接受的。例如,在缓存系统中,CopyOnWriteArraySet 可以用来存储热点数据,因为这些数据通常被频繁读取,而修改操作相对较少。

📝 3. 避免使用锁的场景

在多线程环境下,使用锁可以保证数据的一致性,但会增加程序的复杂度。CopyOnWriteArraySet 可以避免使用锁,从而简化程序设计。例如,在分布式系统中,可以使用 CopyOnWriteArraySet 来存储分布式锁的候选节点,因为节点列表通常被频繁读取,而修改操作相对较少。

📝 4. 需要快速查找的场景

CopyOnWriteArraySet 的查找性能较高,因为它基于数组实现,可以快速定位元素。在需要快速查找元素的场景下,CopyOnWriteArraySet 是一个不错的选择。

🎉 对比与列举

以下表格对比了 CopyOnWriteArraySet 与其他并发集合的特点:

特点CopyOnWriteArraySetConcurrentHashMapCopyOnWriteArrayList
线程安全特性读多写少,保证数据一致性读多写少,保证数据一致性读多写少,保证数据一致性
应用场景需要保证数据一致性的场景,读多写少的场景,避免使用锁的场景,需要快速查找的场景需要保证数据一致性的场景,读多写少的场景,避免使用锁的场景,需要快速查找的场景需要保证数据一致性的场景,读多写少的场景,避免使用锁的场景,需要快速查找的场景
性能分析写性能较低,读性能较高写性能较高,读性能较高写性能较低,读性能较高
内存占用较大,因为每次修改操作都会创建新的数组较小,因为使用分段锁较大,因为每次修改操作都会创建新的数组

🎉 代码示例

以下是一个使用 CopyOnWriteArraySet 的示例:

import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetExample {
    public static void main(String[] args) {
        CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
        set.add("Java");
        set.add("Python");
        set.add("C++");

        for (String language : set) {
            System.out.println(language);
        }
    }
}

在这个示例中,我们创建了一个 CopyOnWriteArraySet,并添加了三个元素。然后,我们遍历这个集合,打印出每个元素。

总结来说,CopyOnWriteArraySet 在读多写少的场景下,可以保证数据的一致性,避免使用锁,并提供快速的查找性能。在实际应用中,可以根据具体需求选择合适的并发集合。

🎉 CopyOnWriteArraySet 优势

CopyOnWriteArraySet 是一种线程安全的集合实现,它通过在每次修改操作时复制底层数组来保证线程安全。以下是 CopyOnWriteArraySet 的主要优势:

优势描述
线程安全由于每次修改操作都会创建一个新的数组,因此不会出现并发修改的问题,保证了线程安全。
无锁设计CopyOnWriteArraySet 使用无锁设计,避免了传统集合中复杂的锁机制,提高了性能。
读操作性能高由于读操作不会修改底层数组,因此读操作的性能非常高。
简洁易用CopyOnWriteArraySet 的 API 简洁易用,易于理解和实现。

🎉 CopyOnWriteArraySet 劣势

尽管 CopyOnWriteArraySet 具有许多优势,但它也有一些明显的劣势:

劣势描述
写操作性能低由于每次写操作都会创建一个新的数组,因此写操作的性能较低,尤其是在集合较大时。
内存消耗大由于每次写操作都会创建一个新的数组,因此内存消耗较大,尤其是在集合较大时。
不适用于频繁修改的场景由于写操作性能低,CopyOnWriteArraySet 不适用于频繁修改的场景。

🎉 总结

CopyOnWriteArraySet 是一种线程安全的集合实现,具有线程安全、无锁设计、读操作性能高、简洁易用等优势。然而,它也存在写操作性能低、内存消耗大、不适用于频繁修改的场景等劣势。在实际应用中,应根据具体需求选择合适的集合实现。

🍊 并发编程核心知识点之CopyOnWriteArraySet:实现原理

在分布式系统中,尤其是在高并发场景下,数据的一致性和线程安全是至关重要的。一个常见的场景是,在一个多线程环境中,多个线程可能同时尝试修改一个共享的集合,如Set集合。如果使用传统的同步集合,如CopyOnWriteArrayList,虽然可以保证线程安全,但在写操作频繁的场景下,其性能会大打折扣,因为每次写操作都会复制整个底层数组。为了解决这个问题,CopyOnWriteArraySet应运而生。

CopyOnWriteArraySet是一种线程安全的集合,它通过在每次修改操作时复制底层数组来保证线程安全。这种策略在写操作不频繁的场景下非常有效,因为它避免了锁的竞争,从而提高了性能。然而,这种策略在写操作频繁的场景下可能会带来性能瓶颈,因为它需要复制整个底层数组。

介绍CopyOnWriteArraySet的实现原理具有重要意义。首先,它可以帮助我们理解在高并发环境下如何保证数据的一致性和线程安全。其次,了解其实现原理有助于我们在实际开发中根据具体场景选择合适的集合类型,以优化系统性能。

接下来,我们将深入探讨CopyOnWriteArraySet的数据结构、写操作处理和读操作处理。首先,我们会介绍CopyOnWriteArraySet的数据结构,包括其底层数组以及如何通过数组索引快速访问元素。然后,我们将详细解析写操作处理机制,包括添加、删除和替换元素时的具体步骤。最后,我们会讨论读操作处理,解释为什么CopyOnWriteArraySet在读取操作上表现出色,即使在高并发环境下也能保持高效。通过这些内容,读者将能够全面理解CopyOnWriteArraySet的工作原理,并在实际开发中灵活运用。

CopyOnWriteArraySet 数据结构

CopyOnWriteArraySet 是 Java 集合框架中的一种线程安全的集合实现,它基于数组来存储元素。与传统的基于数组的集合(如 ArrayList)不同,CopyOnWriteArraySet 在每次修改操作(如 add、remove、set)时,都会创建并复制一个新的数组,并将修改后的元素写入这个新数组中。下面,我们将从数据结构、线程安全特性、实现原理等方面详细探讨 CopyOnWriteArraySet。

🎉 数据结构

CopyOnWriteArraySet 的数据结构相对简单,它内部维护了一个数组,用于存储集合中的元素。这个数组在初始化时会被赋予一个初始容量,当数组容量不足以存储更多元素时,会进行扩容操作。

特性说明
数组用于存储元素
初始容量数组初始化时的容量
扩容策略当数组容量不足以存储更多元素时,会进行扩容操作,扩容策略为:新容量 = 原容量 * 2 + 1

🎉 线程安全特性

CopyOnWriteArraySet 的线程安全特性主要体现在以下几个方面:

  1. 读操作:读操作(如 get、contains、iterator 等)在遍历数组时,不会对数组进行修改,因此可以并发进行。
  2. 写操作:写操作(如 add、remove、set 等)在执行时,会创建并复制一个新的数组,并将修改后的元素写入这个新数组中,从而保证线程安全。

🎉 实现原理

CopyOnWriteArraySet 的实现原理如下:

  1. 初始化:初始化时,创建一个空数组,并设置初始容量。
  2. 读操作:当执行读操作时,直接遍历数组,不会对数组进行修改。
  3. 写操作:当执行写操作时,创建并复制一个新的数组,将修改后的元素写入这个新数组中,然后替换原来的数组。
public class CopyOnWriteArraySet<T> implements Set<T> {
    private volatile transient Object[] array;
    private transient int count;

    public CopyOnWriteArraySet() {
        array = EMPTY_ARRAY;
    }

    public boolean add(E e) {
        Object[] oldArray = array;
        int oldCount = count;
        Object[] newArray = new Object[oldCount + 1];
        System.arraycopy(oldArray, 0, newArray, 0, oldCount);
        newArray[oldCount] = e;
        array = newArray;
        count = oldCount + 1;
        return true;
    }

    public boolean contains(Object o) {
        Object[] array = this.array;
        int n = count;
        for (int i = 0; i < n; i++) {
            if (o.equals(array[i])) {
                return true;
            }
        }
        return false;
    }

    // ... 其他方法 ...
}

🎉 性能分析

CopyOnWriteArraySet 的性能特点如下:

  1. 读操作:读操作性能较高,因为读操作不会对数组进行修改,可以并发进行。
  2. 写操作:写操作性能较低,因为每次写操作都需要创建并复制一个新的数组,这会导致较大的性能开销。

🎉 适用场景

CopyOnWriteArraySet 适用于以下场景:

  1. 读操作频繁:当集合中的读操作远多于写操作时,CopyOnWriteArraySet 可以提供较好的性能。
  2. 数据量较小:当集合中的数据量较小时,CopyOnWriteArraySet 的性能表现较好。

🎉 与其他集合类的比较

集合类特点适用场景
CopyOnWriteArraySet线程安全,读操作性能高,写操作性能低读操作频繁,数据量较小
ConcurrentHashMap线程安全,读操作和写操作性能较高需要并发访问集合
CopyOnWriteArrayList线程安全,读操作和写操作性能较高需要并发访问列表

🎉 使用示例

import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetExample {
    public static void main(String[] args) {
        CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
        set.add("Java");
        set.add("Python");
        set.add("C++");

        System.out.println(set.contains("Java")); // 输出:true
        System.out.println(set.contains("Ruby")); // 输出:false
    }
}

🎉 优缺点分析

优点说明
线程安全适用于多线程环境
读操作性能高读操作不会对数组进行修改,可以并发进行
缺点说明
写操作性能低每次写操作都需要创建并复制一个新的数组,这会导致较大的性能开销
内存占用大由于每次写操作都会创建并复制一个新的数组,因此内存占用较大

CopyOnWriteArraySet 写操作处理

CopyOnWriteArraySet 是 Java 集合框架中的一种线程安全的集合实现,它通过在写操作时复制底层数组来保证线程安全。下面,我们将从多个维度详细探讨 CopyOnWriteArraySet 的写操作处理。

🎉 写操作处理

CopyOnWriteArraySet 的写操作主要包括添加、删除和替换元素。下面,我们将通过表格对比这些操作的处理方式。

操作类型处理方式
添加元素创建一个新的数组,包含原数组和新增元素
删除元素创建一个新的数组,包含原数组中除了被删除元素之外的所有元素
替换元素创建一个新的数组,包含原数组中除了被替换元素之外的所有元素,并将新元素添加到数组中

🎉 线程安全机制

CopyOnWriteArraySet 的线程安全机制主要依赖于写操作时的数组复制。当有线程进行写操作时,其他线程的读操作和写操作都会被阻塞,直到写操作完成。这种机制保证了在多线程环境下,CopyOnWriteArraySet 的数据一致性。

🎉 性能特点

CopyOnWriteArraySet 的性能特点如下:

  • 读操作:读操作非常快,因为它们不需要进行任何同步处理。
  • 写操作:写操作较慢,因为每次写操作都需要复制整个底层数组。

🎉 适用场景

CopyOnWriteArraySet 适用于以下场景:

  • 读操作远多于写操作:在这种情况下,CopyOnWriteArraySet 的读操作性能优势可以充分发挥。
  • 数据量较小:因为每次写操作都需要复制整个底层数组,所以数据量较大的情况下,CopyOnWriteArraySet 的性能会受到影响。

🎉 与其他集合类的比较

与 CopyOnWriteArraySet 相比,以下集合类在写操作处理方面有所不同:

集合类写操作处理
ConcurrentHashMap使用分段锁,保证线程安全,但写操作性能较慢
CopyOnWriteArrayList与 CopyOnWriteArraySet 类似,但适用于列表结构
Vector使用同步方法保证线程安全,但写操作性能较慢

🎉 实现原理

CopyOnWriteArraySet 的实现原理如下:

  1. 使用一个可变数组作为底层数组。
  2. 在进行写操作时,复制底层数组,并修改复制后的数组。
  3. 将修改后的数组赋值给原数组。

🎉 使用示例

以下是一个使用 CopyOnWriteArraySet 的示例:

import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetExample {
    public static void main(String[] args) {
        CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
        set.add("Java");
        set.add("Python");
        set.add("C++");

        System.out.println("Original Set: " + set);

        set.remove("Java");
        System.out.println("After removing Java: " + set);
    }
}

🎉 优缺点分析

CopyOnWriteArraySet 的优缺点如下:

优点

  • 线程安全,无需担心并发问题。
  • 读操作性能高。

缺点

  • 写操作性能低,因为每次写操作都需要复制整个底层数组。
  • 不适用于数据量较大的场景。

🎉 并发控制策略

CopyOnWriteArraySet 的并发控制策略如下:

  1. 当有线程进行写操作时,其他线程的读操作和写操作都会被阻塞。
  2. 写操作完成后,其他线程的读操作和写操作可以继续执行。

总结来说,CopyOnWriteArraySet 是一种适用于读操作远多于写操作的场景的线程安全集合。在写操作处理方面,它通过复制底层数组来保证线程安全,但这也导致了写操作性能较低。在实际应用中,应根据具体场景选择合适的集合类。

🎉 读操作处理

在并发编程中,CopyOnWriteArraySet 是一种线程安全的集合实现,它通过在每次修改操作时创建并复制底层数组来保证线程安全。下面,我们将从多个维度深入探讨 CopyOnWriteArraySet 的读操作处理。

📝 线程安全

CopyOnWriteArraySet 的线程安全主要依赖于其读操作。在 CopyOnWriteArraySet 中,所有的读操作都是直接在底层数组上进行的,而不需要额外的同步措施。这是因为底层数组在写操作时会被复制,从而保证了读操作的一致性和线程安全。

📝 性能特点
特点说明
读操作性能由于读操作直接在底层数组上进行,因此读操作的性能非常高。
写操作性能写操作需要复制整个底层数组,因此写操作的性能较低。
📝 适用场景

CopyOnWriteArraySet 适用于读多写少的场景,例如缓存、日志记录等。

📝 实现原理
public class CopyOnWriteArraySet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable {
    private transient volatile Object[] array;

    public boolean add(E e) {
        Object[] es;
        int len;
        Object oldVal;
        synchronized (this) {
            es = this.array;
            if (es != null) {
                len = es.length;
            } else {
                len = 0;
            }
            if (e == null) {
                throw new NullPointerException();
            }
            if (contains(e)) {
                return false;
            }
            Object[] newEs = Arrays.copyOf(es, len + 1);
            newEs[len] = e;
            oldVal = this.array = newEs;
        }
        return (oldVal == null) ? true : (oldVal != e);
    }
}
📝 与 ConcurrentHashMap 关系

CopyOnWriteArraySet 是基于 ConcurrentHashMap 的 putIfAbsent 方法实现的。ConcurrentHashMap 提供了线程安全的 Map 实现,而 CopyOnWriteArraySet 则是线程安全的 Set 实现。

📝 与 CopyOnWriteArrayList 比较
特点CopyOnWriteArraySetCopyOnWriteArrayList
读操作性能
写操作性能
适用场景读多写少读多写少
📝 优缺点分析
优点缺点
优点- 线程安全<br>- 读操作性能高- 写操作性能低<br>- 内存占用大
缺点- 写操作性能低<br>- 内存占用大- 写操作性能低
📝 实际应用案例

在缓存系统中,CopyOnWriteArraySet 可以用来存储缓存键值对。由于缓存系统通常读操作较多,写操作较少,因此使用 CopyOnWriteArraySet 可以保证线程安全的同时,提高读操作的性能。

总之,CopyOnWriteArraySet 是一种高效的线程安全集合实现,适用于读多写少的场景。在实际应用中,可以根据具体需求选择合适的线程安全集合。

🍊 并发编程核心知识点之CopyOnWriteArraySet:使用方法

在许多需要处理大量并发访问的场景中,如分布式缓存系统、高并发Web应用等,数据结构的线程安全性变得尤为重要。一个典型的场景是,在一个高并发的系统中,多个线程可能同时尝试修改一个共享的集合,如添加、删除或遍历集合中的元素。如果使用普通的线程不安全的集合,如HashSet,可能会导致数据不一致或并发错误。为了解决这个问题,CopyOnWriteArraySet应运而生。

CopyOnWriteArraySet是一种线程安全的集合,它通过在每次修改操作时复制底层数组来保证线程安全。这种策略在写操作相对较少而读操作频繁的场景中特别有效。下面,我们将详细介绍CopyOnWriteArraySet的使用方法,包括其初始化、添加元素、删除元素以及遍历元素等操作。

介绍CopyOnWriteArraySet的使用方法对于理解和应用这种数据结构至关重要。它不仅能够确保在高并发环境下数据的一致性,而且由于其写时复制的设计,可以显著减少锁的竞争,提高系统的吞吐量。这对于需要处理大量并发请求的应用来说,是一个非常重要的知识点。

接下来,我们将依次介绍CopyOnWriteArraySet的初始化方法,以及如何安全地添加、删除和遍历集合中的元素。首先,初始化部分将解释如何创建一个CopyOnWriteArraySet实例,并了解其默认行为。然后,我们将探讨如何安全地添加元素到集合中,包括处理可能的并发问题。删除元素部分将介绍如何从集合中移除元素,并确保操作的原子性。最后,遍历元素部分将展示如何安全地迭代CopyOnWriteArraySet中的元素,同时保持线程安全。通过这些详细的介绍,读者将能够全面掌握CopyOnWriteArraySet的使用技巧,并在实际开发中有效地应用这一数据结构。

CopyOnWriteArraySet 是 Java 集合框架中的一种线程安全的集合实现,它通过在每次修改操作时复制整个底层数组来保证线程安全。下面,我们将从多个维度详细探讨 CopyOnWriteArraySet 的初始化过程。

🎉 初始化过程

CopyOnWriteArraySet 的初始化相对简单,主要涉及以下几个方面:

  1. 无参构造函数:创建一个空的 CopyOnWriteArraySet 实例。
  2. 有参构造函数:接受一个 Collection 参数,初始化时将参数中的元素添加到 Set 中。
📝 无参构造函数
public CopyOnWriteArraySet() {
    this.set = Collections.emptySet();
}
📝 有参构造函数
public CopyOnWriteArraySet(Collection<? extends E> c) {
    Object[] elements;
    if (c.getClass() == this.getClass()) {
        @SuppressWarnings("unchecked")
        CopyOnWriteArraySet<E> cs = (CopyOnWriteArraySet<E>) c;
        elements = cs.set;
    } else {
        elements = c.toArray();
        if (elements.length == c.size()) {
            return;
        }
    }
    this.set = Arrays.copyOf(elements, elements.length, Object[].class);
}

🎉 数据结构

CopyOnWriteArraySet 的内部数据结构是一个可变数组。它使用 Object[] 作为底层数组来存储元素,并使用 HashSet 的逻辑来保证元素的唯一性。

🎉 线程安全特性

CopyOnWriteArraySet 的线程安全特性主要体现在以下几个方面:

  • 读操作:所有读操作都是直接在底层数组上进行的,无需加锁。
  • 写操作:每次写操作(添加、删除、替换等)都会创建一个新的底层数组,并将修改后的元素复制到新数组中。

🎉 内存占用分析

由于每次写操作都会创建一个新的底层数组,因此 CopyOnWriteArraySet 的内存占用相对较高。特别是在集合较大时,频繁的写操作会导致内存占用急剧增加。

🎉 性能影响

CopyOnWriteArraySet 的性能主要受以下因素影响:

  • 写操作:由于每次写操作都需要复制整个底层数组,因此写操作的性能较低。
  • 读操作:读操作的性能较高,因为它们可以直接在底层数组上进行。

🎉 适用场景

CopyOnWriteArraySet 适用于以下场景:

  • 读操作远多于写操作:由于读操作性能较高,因此适用于读操作频繁的场景。
  • 集合较小:由于内存占用较高,因此适用于集合较小的场景。

🎉 与其他集合类的比较

集合类线程安全初始化方式写操作性能读操作性能
CopyOnWriteArraySet无参构造函数、有参构造函数
ConcurrentHashMap无参构造函数、有参构造函数
Collections.synchronizedSet包装现有集合

🎉 初始化参数配置

CopyOnWriteArraySet 的初始化参数配置相对简单,主要涉及以下两个方面:

  • 无参构造函数:无参数配置。
  • 有参构造函数:接受一个 Collection 参数,初始化时将参数中的元素添加到 Set 中。

🎉 初始化时机

CopyOnWriteArraySet 的初始化时机主要有以下两种:

  • 静态初始化:在类加载时初始化。
  • 动态初始化:在程序运行时创建实例时初始化。

🎉 初始化优化策略

为了降低 CopyOnWriteArraySet 的内存占用和性能损耗,可以采取以下优化策略:

  • 限制集合大小:尽量减少集合中的元素数量。
  • 延迟初始化:在需要时才创建 CopyOnWriteArraySet 实例。
  • 使用其他线程安全集合:根据实际需求选择合适的线程安全集合。

🎉 CopyOnWriteArraySet 添加元素

在并发编程中,CopyOnWriteArraySet 是一种线程安全的集合实现,它通过在每次修改操作时复制底层数组来保证线程安全。下面,我们将从多个维度详细探讨 CopyOnWriteArraySet 的添加元素过程。

📝 线程安全机制

CopyOnWriteArraySet 的线程安全机制主要体现在以下几个方面:

  • 写时复制(Copy-On-Write):当有元素添加到集合中时,它会创建一个新的数组,并将新元素添加到这个新数组中,然后替换掉原来的数组。
  • 读操作无锁:由于读操作不会修改底层数组,因此可以并行进行,不会产生线程安全问题。
📝 性能特点
特点说明
优点- 线程安全,无需担心并发修改问题<br>- 读操作性能高,因为读操作不会修改底层数组- 写操作性能较差,因为每次写操作都需要复制整个底层数组<br>- 内存占用较大,因为需要存储多个数组
缺点- 写操作性能较差,因为每次写操作都需要复制整个底层数组<br>- 内存占用较大,因为需要存储多个数组- 读操作性能高,因为读操作不会修改底层数组
📝 适用场景

CopyOnWriteArraySet 适用于以下场景:

  • 读多写少:当集合中的读操作远多于写操作时,CopyOnWriteArraySet 可以提供较好的性能。
  • 读操作频繁:由于读操作无锁,CopyOnWriteArraySet 适用于读操作频繁的场景。
📝 与其他集合类的比较
集合类特点适用场景
CopyOnWriteArraySet写时复制,线程安全,读操作无锁读多写少,读操作频繁
ConcurrentHashMap线程安全,读操作无锁,写操作加锁读多写少,读操作频繁
Vector线程安全,读操作无锁,写操作加锁读多写少,读操作频繁
ArrayList线程不安全,读操作无锁,写操作加锁读多写少,读操作频繁
📝 实现原理

CopyOnWriteArraySet 的实现原理如下:

  1. 使用一个 Object 数组作为底层数组。
  2. 当添加元素时,创建一个新的数组,并将新元素添加到这个新数组中。
  3. 替换掉原来的数组。
public class CopyOnWriteArraySet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable {
    private transient volatile Object[] array;

    public boolean add(E e) {
        Object[] es;
        synchronized (this) {
            es = getArray();
            int len = es.length;
            if (e == null) {
                throw new NullPointerException();
            }
            for (int i = 0; i < len; i++) {
                if (e.equals(es[i])) {
                    return false;
                }
            }
            Object[] newEs = Arrays.copyOf(es, len + 1);
            newEs[len] = e;
            setArray(newEs);
        }
        return true;
    }

    private void setArray(Object[] a) {
        array = a;
    }

    private Object[] getArray() {
        return array;
    }
}
📝 源码分析

在上面的代码中,我们可以看到 CopyOnWriteArraySet 的 add 方法:

  1. 使用 synchronized 关键字同步代码块,保证线程安全。
  2. 获取当前底层数组。
  3. 遍历数组,判断新元素是否已存在。
  4. 如果不存在,创建一个新的数组,并将新元素添加到这个新数组中。
  5. 替换掉原来的数组。
📝 使用注意事项
  • 避免频繁的写操作:由于每次写操作都需要复制整个底层数组,因此频繁的写操作会导致性能下降。
  • 内存占用:由于需要存储多个数组,因此内存占用较大。
  • 适用于读多写少的场景:CopyOnWriteArraySet 适用于读多写少的场景,如果写操作频繁,建议使用其他线程安全的集合类。

🎉 CopyOnWriteArraySet 删除元素

在并发编程中,CopyOnWriteArraySet 是一种线程安全的集合实现,它通过复制底层数组来保证在并发环境下的线程安全。下面,我们将深入探讨 CopyOnWriteArraySet 的删除元素操作。

📝 原理分析

CopyOnWriteArraySet 的删除元素操作与添加元素类似,其核心原理如下:

  1. 当调用删除方法时,首先会复制底层数组的一个副本。
  2. 在副本上进行删除操作,即从副本中移除指定的元素。
  3. 删除完成后,将副本赋值给底层数组,从而实现删除操作。

这种操作方式保证了在删除过程中,其他线程对集合的访问不会受到影响,因为它们访问的是原始数组。

📝 性能影响

CopyOnWriteArraySet 的删除操作相较于其他线程安全集合(如 ConcurrentHashMap 的 keySet 视图)来说,性能较低。原因如下:

  1. 删除操作需要复制整个底层数组,这在数据量大时会导致较大的性能开销。
  2. 由于每次删除操作都会创建新的数组,因此会占用更多的内存空间。
📝 适用场景

CopyOnWriteArraySet 适用于以下场景:

  1. 集合中的元素数量较少,且读操作远多于写操作。
  2. 集合中的元素不可变,即删除操作不会改变元素的值。
📝 与其他集合类的比较
集合类删除操作特点
CopyOnWriteArraySet复制底层数组,删除元素,性能较低,适用于读多写少的场景
ConcurrentHashMap 的 keySet 视图直接在底层数组上进行删除操作,性能较高,适用于读多写少的场景
Vector同步方法进行删除操作,性能较低,适用于读多写少的场景
Collections.synchronizedSet同步方法进行删除操作,性能较低,适用于读多写少的场景
📝 使用注意事项
  1. 避免在集合中存储大量元素,因为每次删除操作都会复制整个底层数组。
  2. 确保集合中的元素不可变,以避免在删除操作中修改元素的值。
📝 代码示例
import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetExample {
    public static void main(String[] args) {
        CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
        set.add("Java");
        set.add("Python");
        set.add("C++");

        // 删除元素
        set.remove("Python");

        // 打印集合
        System.out.println(set);
    }
}
📝 实际应用案例

在分布式系统中,CopyOnWriteArraySet 可以用于存储需要保持线程安全的配置信息。例如,在分布式缓存系统中,可以使用 CopyOnWriteArraySet 来存储缓存节点的信息,确保在并发环境下,缓存节点的信息不会被错误地修改。

🎉 CopyOnWriteArraySet 特性

CopyOnWriteArraySet 是 Java 集合框架中的一种线程安全的集合实现,它基于数组来实现。其核心特性如下:

特性说明
线程安全通过写时复制(Copy-On-Write)机制实现线程安全,适用于读多写少的并发场景。
无锁设计采用无锁设计,避免了传统集合在并发环境下可能出现的线程安全问题。
迭代器安全迭代器是快速失败的,即当有线程修改集合时,迭代器会抛出 ConcurrentModificationException 异常。

🎉 遍历方法

CopyOnWriteArraySet 提供了多种遍历方法,以下列举几种常用的遍历方式:

方法说明
iterator()返回一个迭代器,用于遍历集合中的元素。
forEach(Consumer<? super E> action)使用提供的 Consumer 接口接受每个元素。
stream()返回一个流,可以用于并行处理集合中的元素。

🎉 线程安全机制

CopyOnWriteArraySet 的线程安全机制主要依赖于以下两个方面:

  1. 写时复制:当有线程对集合进行修改操作(如 add、remove 等)时,会创建一个新的数组,并将原数组中的元素复制到新数组中,然后替换原数组。这样,读操作始终在原数组上进行,保证了线程安全。

  2. 迭代器快速失败:当有线程修改集合时,迭代器会抛出 ConcurrentModificationException 异常,从而避免并发修改导致的数据不一致问题。

🎉 与 ConcurrentHashMap 的关系

CopyOnWriteArraySet 和 ConcurrentHashMap 都是 Java 集合框架中的线程安全集合实现。它们之间的主要区别如下:

对比项CopyOnWriteArraySetConcurrentHashMap
数据结构基于数组基于分段锁的哈希表
适用场景读多写少的并发场景读多写多、高并发场景
性能读写性能较差读写性能较好

🎉 适用场景

CopyOnWriteArraySet 适用于以下场景:

  1. 读多写少的并发场景,如缓存、日志记录等。
  2. 需要保证迭代器安全性的场景。

🎉 性能分析

CopyOnWriteArraySet 的性能特点如下:

性能指标说明
读性能较好,因为读操作始终在原数组上进行。
写性能较差,因为写操作需要创建新的数组并复制元素。
空间复杂度较高,因为需要存储多个数组。

🎉 与其他集合类的比较

以下表格对比了 CopyOnWriteArraySet 与其他集合类的特点:

集合类特点
HashSet非线程安全,适用于读多写少的场景。
Vector线程安全,但性能较差。
CopyOnWriteArrayList线程安全,但适用于读多写少的场景。

🎉 使用注意事项

  1. 避免在写操作频繁的场景中使用 CopyOnWriteArraySet,因为其写性能较差。
  2. 注意迭代器的使用,避免并发修改导致的数据不一致问题。

🎉 实际应用案例

以下是一个使用 CopyOnWriteArraySet 的实际应用案例:

import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetExample {
    public static void main(String[] args) {
        CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
        set.add("Java");
        set.add("Python");
        set.add("C++");

        for (String language : set) {
            System.out.println(language);
        }
    }
}

在这个例子中,我们创建了一个 CopyOnWriteArraySet 集合,并添加了三个元素。然后,我们遍历集合并打印每个元素。由于 CopyOnWriteArraySet 是线程安全的,所以在这个例子中,即使有多个线程同时修改集合,也不会出现数据不一致的问题。

🍊 并发编程核心知识点之CopyOnWriteArraySet:性能分析

在当今的多核处理器时代,并发编程已经成为提高程序性能的关键技术之一。特别是在处理大量数据或需要高并发访问的场景中,如何有效地管理数据结构以支持并发操作变得尤为重要。一个典型的场景是,在一个分布式系统中,多个节点需要共享一个数据集,并且这些节点之间需要频繁地进行读写操作。在这种情况下,如果使用传统的线程安全集合,如ConcurrentHashMap,虽然能够保证线程安全,但其写操作的性能可能会成为瓶颈。为了解决这个问题,CopyOnWriteArraySet应运而生。

CopyOnWriteArraySet是一种线程安全的集合,它通过在每次修改操作时复制底层数组来保证线程安全。这种策略在写操作较少而读操作频繁的场景中表现出色,因为它避免了复杂的锁机制,从而减少了写操作的延迟。然而,这种策略在写操作频繁的场景中可能会带来性能问题,因为每次写操作都需要复制整个底层数组。

介绍CopyOnWriteArraySet的性能分析对于理解其适用场景和优化并发程序至关重要。它不仅可以帮助我们评估CopyOnWriteArraySet在不同场景下的性能表现,还可以指导我们在实际应用中选择合适的并发数据结构。

接下来,我们将深入探讨CopyOnWriteArraySet的三个关键方面:读操作性能、写操作性能以及适用场景分析。首先,我们将分析CopyOnWriteArraySet在执行读操作时的性能特点,包括其数据一致性和访问速度。然后,我们将探讨写操作的性能瓶颈,并分析为什么在某些情况下写操作可能会成为性能瓶颈。最后,我们将讨论CopyOnWriteArraySet的适用场景,包括它最适合解决哪些类型的问题,以及在使用时需要注意哪些潜在的性能问题。通过这些分析,读者将能够更好地理解CopyOnWriteArraySet的工作原理,并在实际开发中做出明智的选择。

🎉 读操作性能

在并发编程中,CopyOnWriteArraySet 是一种线程安全的集合实现,它通过在每次修改操作时创建并复制底层数组来保证线程安全。下面,我们将从多个维度深入探讨 CopyOnWriteArraySet 的读操作性能。

📝 与 CopyOnWriteArrayList 比较表格
比较维度CopyOnWriteArraySetCopyOnWriteArrayList
线程安全
内存占用
读操作性能
写操作性能
适用场景频繁读操作,写操作较少的场景频繁写操作,读操作较多的场景

解释:从表格中可以看出,CopyOnWriteArraySet 在读操作性能上优于 CopyOnWriteArrayList,但在写操作性能上则相对较低。

📝 实现原理

CopyOnWriteArraySet 的实现原理是,每次修改操作(如 add、remove 等)都会创建一个新的底层数组,并将修改后的元素复制到新数组中。这样,读操作始终在原始数组上进行,保证了线程安全。

public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        int len = elements.length;
        if (e == null) {
            for (int i = 0; i < len; i++)
                if (elements[i] == null)
                    return false;
        } else {
            for (int i = 0; i < len; i++)
                if (e.equals(elements[i]))
                    return false;
        }
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        newElements[len] = e;
        setArray(newElements);
        return true;
    } finally {
        lock.unlock();
    }
}
📝 使用示例
import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetExample {
    public static void main(String[] args) {
        CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
        set.add("Java");
        set.add("Python");
        set.add("C++");

        System.out.println(set); // 输出: [Java, Python, C++]
    }
}
📝 优缺点分析

优点

  • 读操作性能高,因为读操作始终在原始数组上进行,无需加锁。
  • 线程安全,适用于读操作频繁、写操作较少的场景。

缺点

  • 写操作性能低,因为每次修改操作都需要创建新的底层数组,并复制元素。
  • 内存占用高,因为每次修改操作都会创建新的底层数组。
📝 适用场景

CopyOnWriteArraySet 适用于以下场景:

  • 频繁读操作,写操作较少的场景。
  • 对性能要求较高的并发场景。
  • 需要保证线程安全的场景。
📝 与 ConcurrentHashMap 关系

CopyOnWriteArraySet 和 ConcurrentHashMap 都是基于 CopyOnWrite 的思想实现的,但它们在应用场景和性能上有所不同。ConcurrentHashMap 适用于频繁写操作的场景,而 CopyOnWriteArraySet 适用于频繁读操作、写操作较少的场景。

📝 总结

CopyOnWriteArraySet 在读操作性能上具有优势,适用于读操作频繁、写操作较少的场景。然而,其写操作性能较低,内存占用较高。在实际应用中,应根据具体场景选择合适的集合实现。

🎉 写操作性能

在并发编程中,CopyOnWriteArraySet 是一种线程安全的集合实现,它通过在写操作时复制底层数组来保证线程安全。下面,我们将从多个维度深入探讨 CopyOnWriteArraySet 的写操作性能。

📝 写操作性能分析

CopyOnWriteArraySet 的写操作主要包括添加、删除和替换元素。下面,我们将通过表格对比这些操作的性能。

操作类型CopyOnWriteArraySet其他线程安全集合
添加元素O(n)O(1)
删除元素O(n)O(1)
替换元素O(n)O(1)

解释:在 CopyOnWriteArraySet 中,每次写操作都会创建一个新的数组,并将修改后的元素复制到新数组中。因此,写操作的时间复杂度为 O(n),其中 n 是集合中元素的数量。相比之下,其他线程安全集合(如 ConcurrentHashMap 的 keySet 视图)的写操作时间复杂度为 O(1)。

📝 并发控制机制

CopyOnWriteArraySet 的并发控制机制是通过在写操作时锁定整个集合来实现的。具体来说,每次写操作都会创建一个新的数组,并将修改后的元素复制到新数组中。这个过程称为“写复制”。

public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        int len = elements.length;
        if (e == null) {
            for (int i = 0; i < len; i++)
                if (elements[i] == null)
                    return false;
        } else {
            for (int i = 0; i < len; i++)
                if (elements[i] == e)
                    return false;
        }
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        newElements[len] = e;
        setArray(newElements);
        return true;
    } finally {
        lock.unlock();
    }
}
📝 线程安全特性

CopyOnWriteArraySet 的线程安全特性主要体现在以下几个方面:

  1. 写操作时,通过锁定整个集合来保证线程安全。
  2. 读取操作不会受到写操作的影响,因为读取的是写操作之前的数组。
  3. 写操作会创建一个新的数组,并将修改后的元素复制到新数组中,从而保证线程安全。
📝 适用场景

CopyOnWriteArraySet 适用于以下场景:

  1. 集合中元素数量较少,且读操作远多于写操作。
  2. 集合中的元素是不可变的,或者可以接受在写操作期间读取到过时的数据。
📝 性能对比

与 ConcurrentHashMap 的 keySet 视图相比,CopyOnWriteArraySet 在写操作性能上存在较大差距。然而,在特定场景下,CopyOnWriteArraySet 仍然具有优势。

📝 内存占用分析

CopyOnWriteArraySet 的内存占用主要取决于以下因素:

  1. 集合中元素的数量。
  2. 元素类型的大小。
📝 写操作优化策略

为了提高 CopyOnWriteArraySet 的写操作性能,可以考虑以下优化策略:

  1. 使用更小的元素类型。
  2. 在写操作之前,尽量减少对集合的读取操作。
  3. 使用更高效的数组复制方法。
📝 与其他集合类的比较

与 ConcurrentHashMap 的 keySet 视图相比,CopyOnWriteArraySet 在写操作性能上存在较大差距。然而,在特定场景下,CopyOnWriteArraySet 仍然具有优势。

📝 实际应用案例

在实际项目中,CopyOnWriteArraySet 可以用于以下场景:

  1. 缓存数据,如缓存用户信息。
  2. 需要保证线程安全的场景,如多线程环境下的数据统计。

总之,CopyOnWriteArraySet 在写操作性能上存在一定劣势,但在特定场景下仍然具有优势。在实际应用中,应根据具体需求选择合适的集合类。

CopyOnWriteArraySet 原理

CopyOnWriteArraySet 是 Java 集合框架中的一种线程安全的集合实现,它基于数组来实现。其核心原理是“写时复制”,即在每次修改操作(如添加、删除、替换等)时,都会创建一个新的数组,并将修改后的元素复制到新数组中,而不是在原数组上进行修改。

线程安全机制

CopyOnWriteArraySet 的线程安全机制主要依赖于以下两点:

  1. 只读共享:在 CopyOnWriteArraySet 中,读操作(如遍历、查找等)不会修改底层数组,因此可以并行进行,不会产生线程安全问题。
  2. 写操作加锁:写操作(如添加、删除、替换等)会先复制原数组,然后在新的数组上进行修改,最后将新数组赋值给底层数组。这个过程需要加锁,以保证在写操作进行时,不会有其他线程进行读或写操作。

适用场景分析

CopyOnWriteArraySet 适用于以下场景:

场景说明
读多写少由于写操作会复制整个数组,因此适用于读操作远多于写操作的场景。
读操作频繁由于读操作不会加锁,因此适用于读操作频繁的场景。
数据量小由于写操作会复制整个数组,因此适用于数据量小的场景。
无序集合由于 CopyOnWriteArraySet 是基于数组实现的,因此它是一个无序集合。

性能特点

CopyOnWriteArraySet 的性能特点如下:

特点说明
读操作性能高由于读操作不会加锁,因此性能较高。
写操作性能低由于写操作会复制整个数组,因此性能较低。
内存占用大由于每次写操作都会复制整个数组,因此内存占用较大。

与其他集合类的比较

集合类说明
HashSet基于哈希表实现,读操作性能高,但写操作性能较低。
ArrayList基于数组实现,读操作性能高,但写操作性能较低。
LinkedList基于链表实现,读操作性能较低,但写操作性能较高。

使用示例

import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetExample {
    public static void main(String[] args) {
        CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
        set.add("Java");
        set.add("Python");
        set.add("C++");

        System.out.println(set); // 输出: [Java, Python, C++]
    }
}

最佳实践

  1. 在读多写少的场景下使用 CopyOnWriteArraySet。
  2. 在数据量小的场景下使用 CopyOnWriteArraySet。
  3. 避免在写操作频繁的场景下使用 CopyOnWriteArraySet。

适用限制

  1. 写操作频繁的场景。
  2. 数据量大的场景。
  3. 对性能要求较高的场景。

与读写锁的比较

特点读写锁CopyOnWriteArraySet
读操作性能
写操作性能
内存占用较低较高
适用场景读多写多读多写少

总结

CopyOnWriteArraySet 是一种线程安全的集合实现,适用于读多写少、读操作频繁、数据量小的场景。它具有读操作性能高、写操作性能低、内存占用大的特点。与其他集合类相比,CopyOnWriteArraySet 在读操作性能上具有优势,但在写操作性能和内存占用上存在不足。在实际应用中,应根据具体场景选择合适的集合类。

🍊 并发编程核心知识点之CopyOnWriteArraySet:与其他集合类的比较

在许多需要处理大量并发访问的场景中,如分布式缓存系统、高并发Web应用等,集合类的选择变得尤为重要。一个常见的场景是,当系统需要保证线程安全且对性能要求较高时,如何选择合适的集合类来存储数据成为了一个关键问题。这就引出了今天要介绍的知识点——并发编程核心知识点之CopyOnWriteArraySet:与其他集合类的比较。

CopyOnWriteArraySet是一种线程安全的集合实现,它通过在每次修改操作时创建并复制底层数组来保证线程安全。这种策略在写操作较少而读操作频繁的场景下非常有效,因为它避免了复杂的同步机制,从而减少了锁的竞争,提高了性能。然而,在写操作频繁的场景下,CopyOnWriteArraySet的性能可能会受到较大影响,因为它需要复制整个底层数组。

介绍CopyOnWriteArraySet与其他集合类的比较,其重要性和实用性体现在以下几个方面:

  1. 性能考量:了解CopyOnWriteArraySet与其他集合类(如HashSet、CopyOnWriteArrayList、ConcurrentHashMap等)的性能差异,有助于开发者根据具体应用场景选择最合适的集合类,以优化系统性能。

  2. 适用场景分析:通过比较,可以明确CopyOnWriteArraySet在哪些场景下表现最佳,哪些场景下可能不是最佳选择,从而指导实际开发。

  3. 线程安全机制理解:深入理解CopyOnWriteArraySet的线程安全机制,有助于开发者更好地理解并发编程中的线程安全问题,并设计出更安全的并发程序。

接下来,我们将对以下三级标题内容进行概述:

  • 并发编程核心知识点之CopyOnWriteArraySet:与HashSet的比较:我们将分析CopyOnWriteArraySet与HashSet在性能、线程安全性和适用场景上的差异,帮助读者了解何时选择CopyOnWriteArraySet而不是HashSet。

  • 并发编程核心知识点之CopyOnWriteArraySet:与CopyOnWriteArrayList的比较:我们将比较CopyOnWriteArraySet和CopyOnWriteArrayList在数据结构和线程安全性上的异同,以及它们在不同应用场景下的表现。

  • 并发编程核心知识点之CopyOnWriteArraySet:与ConcurrentHashMap的比较:我们将探讨CopyOnWriteArraySet和ConcurrentHashMap在实现线程安全方面的不同策略,以及它们在处理集合操作时的性能特点。

通过这些比较,读者可以建立起对CopyOnWriteArraySet及其相关集合类的全面认知,为实际开发提供理论支持。

🎉 CopyOnWriteArraySet 特性

CopyOnWriteArraySet 是 Java 并发集合框架中的一个类,它基于 CopyOnWriteArrayList 实现。其核心特性如下:

特性描述
写时复制当进行添加、删除、替换等写操作时,会创建一个新的数组,并将修改后的元素复制到新数组中,然后替换原有的数组。
线程安全由于写操作会创建新的数组,因此读操作可以并行进行,不会受到写操作的影响,保证了线程安全。
性能写操作的性能较差,因为需要创建新的数组并复制元素,但读操作的性能较好。

🎉 HashSet 特性

HashSet 是 Java 并发集合框架中的一个类,它基于哈希表实现。其核心特性如下:

特性描述
基于哈希表使用哈希表存储元素,具有良好的查找性能。
线程不安全在多线程环境下,HashSet 不是线程安全的,需要使用其他线程安全机制(如 Collections.synchronizedSet)来保证线程安全。
性能查找、添加、删除等操作的平均性能较好,但最坏情况下性能较差。

🎉 并发编程场景

CopyOnWriteArraySet 和 HashSet 都适用于并发编程场景,以下是一些具体的场景:

场景CopyOnWriteArraySetHashSet
元素数量较少适合适合
读操作较多,写操作较少适合适合
写操作频繁不适合适合

🎉 线程安全机制

CopyOnWriteArraySet 和 HashSet 的线程安全机制如下:

类别CopyOnWriteArraySetHashSet
线程安全机制写时复制使用 Collections.synchronizedSet 或其他线程安全机制
优点无需额外的线程安全机制简单易用
缺点写操作性能较差需要额外的线程安全机制

🎉 性能对比

以下表格对比了 CopyOnWriteArraySet 和 HashSet 在不同操作下的性能:

操作CopyOnWriteArraySetHashSet
查找较好较好
添加较差较好
删除较差较好
替换较差较好

🎉 适用场景

CopyOnWriteArraySet 和 HashSet 的适用场景如下:

场景CopyOnWriteArraySetHashSet
元素数量较少,读操作较多适合适合
元素数量较多,写操作频繁不适合适合
元素数量较多,读操作较多适合适合

🎉 内存占用

CopyOnWriteArraySet 和 HashSet 的内存占用如下:

类别CopyOnWriteArraySetHashSet
内存占用较大较小
原因写操作频繁创建新数组基于哈希表,内存占用较小

🎉 实现原理

CopyOnWriteArraySet 的实现原理如下:

public class CopyOnWriteArraySet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable {
    private transient volatile Object[] array;

    public boolean add(E e) {
        Object[] es;
        int len;
        Object oldVal;
        synchronized (this) {
            es = this.array;
            if (es != null) {
                len = es.length;
            } else {
                len = 0;
            }
            if (e == null) {
                throw new NullPointerException();
            }
            if (contains(e)) {
                return false;
            }
            Object[] newEs = Arrays.copyOf(es, len + 1);
            newEs[len] = e;
            oldVal = this.array;
            this.array = newEs;
        }
        System.arraycopy(oldVal, 0, newEs, 0, len);
        return true;
    }
}

HashSet 的实现原理如下:

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable {
    private transient HashMap<E, Object> map;

    public boolean add(E e) {
        return map.put(e, PRESENT) == null;
    }
}

🎉 使用示例

以下是一个使用 CopyOnWriteArraySet 的示例:

import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetExample {
    public static void main(String[] args) {
        CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
        set.add("Java");
        set.add("Python");
        set.add("C++");
        System.out.println(set);
    }
}

以下是一个使用 HashSet 的示例:

import java.util.HashSet;

public class HashSetExample {
    public static void main(String[] args) {
        HashSet<String> set = new HashSet<>();
        set.add("Java");
        set.add("Python");
        set.add("C++");
        System.out.println(set);
    }
}

🎉 优缺点分析

CopyOnWriteArraySet 和 HashSet 的优缺点如下:

类别CopyOnWriteArraySetHashSet
优点线程安全,读操作性能较好线程不安全,但简单易用
缺点写操作性能较差,内存占用较大线程不安全,性能较差

🎉 CopyOnWriteArraySet 原理

CopyOnWriteArraySet 是基于 CopyOnWriteArrayList 实现的线程安全集合,其原理是当有修改操作(如 add、remove、set 等)时,它会创建一个新的数组来存储新的元素,而不是在原数组上进行修改。这样,读操作(如 get、contains 等)可以并行进行,因为它们不会修改数组。

🎉 CopyOnWriteArrayList 原理

CopyOnWriteArrayList 同样是基于数组的,其原理与 CopyOnWriteArraySet 类似。当有修改操作时,它会创建一个新的数组,并将修改后的元素复制到新数组中。读操作可以并行进行,因为它们不会修改数组。

🎉 两者数据结构比较

特性CopyOnWriteArraySetCopyOnWriteArrayList
数据结构SetList
修改操作创建新数组创建新数组
读操作并行并行
写操作并行并行
内存占用较大较大

🎉 线程安全机制

CopyOnWriteArraySet 和 CopyOnWriteArrayList 都使用了 CopyOnWrite 的机制来实现线程安全。当有修改操作时,它们会创建一个新的数组,并将修改后的元素复制到新数组中,从而避免了并发修改的问题。

🎉 适用场景

  • CopyOnWriteArraySet:适用于读多写少的场景,如缓存、日志记录等。
  • CopyOnWriteArrayList:适用于读多写少的场景,如缓存、日志记录等。

🎉 性能分析

  • CopyOnWriteArraySetCopyOnWriteArrayList 的读操作性能较好,因为它们可以并行进行。
  • 写操作性能较差,因为需要创建新的数组并复制元素。

🎉 内存占用

CopyOnWriteArraySet 和 CopyOnWriteArrayList 的内存占用较大,因为它们需要存储多个数组。

🎉 与其他并发集合比较

  • ConcurrentHashMap:适用于读多写少的场景,但写操作性能较差。
  • CopyOnWriteArraySetCopyOnWriteArrayList:适用于读多写少的场景,但写操作性能较差。

🎉 使用示例

import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetExample {
    public static void main(String[] args) {
        CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
        set.add("Java");
        set.add("Python");
        set.add("C++");
        System.out.println(set);
    }
}

🎉 优缺点分析

优点

  • 读操作性能较好,可以并行进行。
  • 写操作简单,不需要考虑并发问题。

缺点

  • 写操作性能较差,因为需要创建新的数组并复制元素。
  • 内存占用较大,因为需要存储多个数组。

🎉 与读写锁比较

读写锁(如 ReentrantReadWriteLock)可以提供更好的性能,因为读操作和写操作可以同时进行。但是,读写锁的实现较为复杂,需要考虑更多的并发问题。相比之下,CopyOnWriteArraySet 和 CopyOnWriteArrayList 的实现较为简单,但性能较差。

🎉 CopyOnWriteArraySet 原理

CopyOnWriteArraySet 是基于 CopyOnWriteArrayList 实现的线程安全集合,其核心思想是“写时复制”。当有修改操作(如 add、set、remove)发生时,它会创建当前数组的副本,并在副本上进行修改,最后将这个副本赋值给数组的引用。这样,读操作(如 get、iterator)始终在原始数组上进行,保证了读操作的原子性和线程安全。

🎉 ConcurrentHashMap 原理

ConcurrentHashMap 是基于分段锁(Segment Locking)的并发集合。它将数据结构分为多个段(Segment),每个段有自己的锁。当一个线程访问一个段时,它只需要获取该段的锁,这样就可以减少锁的竞争,提高并发性能。ConcurrentHashMap 还使用了 HashTable 的思想,通过计算键的哈希值来定位数据在哪个段中。

🎉 线程安全机制

集合类型线程安全机制
CopyOnWriteArraySet写时复制
ConcurrentHashMap分段锁

🎉 性能对比

性能指标CopyOnWriteArraySetConcurrentHashMap
读操作
写操作
内存占用
并发级别

🎉 适用场景

集合类型适用场景
CopyOnWriteArraySet需要高并发读操作,且写操作较少的场景
ConcurrentHashMap需要高并发读写操作的场景

🎉 内存占用

CopyOnWriteArraySet 在写操作时需要创建新的数组,因此内存占用较高。ConcurrentHashMap 由于使用了分段锁,内存占用相对较低。

🎉 并发级别

CopyOnWriteArraySet 的并发级别较低,适用于读多写少的场景。ConcurrentHashMap 的并发级别较高,适用于读多写多的场景。

🎉 使用场景

  • CopyOnWriteArraySet:适用于缓存、日志记录等场景,其中数据变化不频繁,但需要保证读操作的高并发。
  • ConcurrentHashMap:适用于缓存、数据库连接池等场景,其中数据变化频繁,需要保证读写操作的高并发。

🎉 优缺点分析

集合类型优点缺点
CopyOnWriteArraySet读操作无锁,线程安全;适用于读多写少的场景写操作性能较差;内存占用较高
ConcurrentHashMap读操作无锁,线程安全;适用于读多写多的场景内存占用较高;写操作性能较差

🎉 实际应用案例

  • CopyOnWriteArraySet:在缓存场景中,可以使用 CopyOnWriteArraySet 来存储缓存数据,保证读操作的高并发。
  • ConcurrentHashMap:在数据库连接池场景中,可以使用 ConcurrentHashMap 来存储连接信息,保证读写操作的高并发。

🎉 与其他并发集合比较

集合类型CopyOnWriteArraySetConcurrentHashMapCopyOnWriteArrayList
线程安全
读操作
写操作
内存占用
并发级别

总结:CopyOnWriteArraySet 和 ConcurrentHashMap 都是线程安全的并发集合,但它们在性能、内存占用和适用场景上有所不同。在实际应用中,应根据具体需求选择合适的并发集合。

🍊 并发编程核心知识点之CopyOnWriteArraySet:注意事项

在许多需要高并发访问集合的场景中,如分布式缓存系统或高并发Web应用,CopyOnWriteArraySet因其线程安全特性而受到青睐。然而,在实际应用中,如果不了解其注意事项,可能会遇到性能瓶颈或适用场景限制。以下将详细探讨CopyOnWriteArraySet的线程安全问题、适用场景限制以及性能影响分析。

在分布式缓存系统中,当多个客户端并发地读写缓存数据时,如果使用传统的线程不安全的集合,如HashSet,可能会导致数据不一致或并发错误。CopyOnWriteArraySet通过在每次修改操作时复制整个底层数组来保证线程安全,从而避免了传统集合在并发修改时可能出现的线程安全问题。

介绍CopyOnWriteArraySet的注意事项至关重要,因为它不仅关系到系统的稳定性,还直接影响性能和资源消耗。在大型系统中,不当使用CopyOnWriteArraySet可能会导致严重的性能问题,如频繁的全数组复制操作会消耗大量内存和CPU资源。

接下来,我们将深入探讨以下三个方面:

  1. 线程安全问题:CopyOnWriteArraySet如何确保在并发环境下数据的一致性,以及可能出现的线程安全问题。
  2. 适用场景限制:CopyOnWriteArraySet在哪些场景下适用,以及在哪些场景下可能不适合使用。
  3. 性能影响分析:CopyOnWriteArraySet的性能特点,包括其优点和缺点,以及在不同场景下的性能表现。

通过这些内容的介绍,读者将能够全面了解CopyOnWriteArraySet的特性和使用方法,从而在实际开发中做出更明智的选择。

🎉 CopyOnWriteArraySet 线程安全机制

在 Java 并发编程中,CopyOnWriteArraySet 是一种线程安全的集合实现,它通过“写时复制”的机制来保证线程安全。下面,我们将从原理、适用场景、性能特点、与其他集合类的比较、使用注意事项、实际应用案例、与读写锁的比较以及并发编程中的应用策略等方面进行详细阐述。

📝 原理分析

CopyOnWriteArraySet 的核心思想是,当有线程对集合进行修改操作(如 add、remove 等)时,不是直接在原集合上进行修改,而是创建一个新的集合,并将修改后的元素复制到新集合中。这样,在多线程环境下,读操作可以并行进行,而写操作则互斥进行,从而保证了线程安全。

特性说明
读操作并行读,无锁
写操作互斥写,写时复制
内存占用相对较高,因为每次写操作都会创建新的集合
📝 适用场景

CopyOnWriteArraySet 适用于读多写少的场景,例如:

  • 数据变化不频繁,但读取操作非常频繁的场景。
  • 需要保证读操作的高效性和线程安全性的场景。
📝 性能特点

CopyOnWriteArraySet 的性能特点如下:

  • 读操作性能高,因为读操作可以并行进行。
  • 写操作性能低,因为每次写操作都需要创建新的集合。
📝 与其他集合类的比较
集合类特点
ConcurrentHashMap线程安全,适用于读多写少的场景,但读操作性能略低于 CopyOnWriteArraySet。
CopyOnWriteArrayList线程安全,适用于读多写少的场景,但读操作性能略低于 CopyOnWriteArraySet。
CopyOnWriteArraySet线程安全,适用于读多写少的场景,读操作性能高,但写操作性能低。
📝 使用注意事项
  • 由于写操作性能较低,因此不适用于写操作频繁的场景。
  • 在迭代器进行迭代时,如果其他线程对集合进行了修改操作,则迭代器会抛出 ConcurrentModificationException 异常。
📝 实际应用案例

以下是一个使用 CopyOnWriteArraySet 的示例:

import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetExample {
    public static void main(String[] args) {
        CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
        set.add("Java");
        set.add("Python");
        set.add("C++");

        for (String language : set) {
            System.out.println(language);
        }
    }
}
📝 与读写锁的比较

读写锁(如 ReentrantReadWriteLock)允许多个读线程同时访问,但写线程会独占访问。与读写锁相比,CopyOnWriteArraySet 在读操作性能上略高,但在写操作性能上较低。

📝 在并发编程中的应用策略
  • 在读多写少的场景下,可以使用 CopyOnWriteArraySet 来保证线程安全。
  • 在写操作频繁的场景下,应考虑使用其他线程安全的集合类,如 ConcurrentHashMap 或 CopyOnWriteArrayList。

通过以上分析,我们可以了解到 CopyOnWriteArraySet 的线程安全机制、原理、适用场景、性能特点、与其他集合类的比较、使用注意事项、实际应用案例以及并发编程中的应用策略。在实际开发中,应根据具体场景选择合适的线程安全集合类,以提高程序的性能和稳定性。

🎉 适用场景限制

在并发编程中,CopyOnWriteArraySet 是一种线程安全的集合实现,它通过在每次修改操作时复制整个底层数组来保证线程安全。然而,由于其独特的实现方式,CopyOnWriteArraySet 在某些场景下并不适用。

📝 对比与列举
特性CopyOnWriteArraySet其他并发集合
线程安全
读操作性能
写操作性能
内存占用
适用场景集合读多写少,且写操作不频繁集合读多写多,或写操作频繁

从上表可以看出,CopyOnWriteArraySet 在读操作性能上表现良好,但在写操作性能上较差,且内存占用较高。因此,它适用于读多写少,且写操作不频繁的场景。

📝 适用场景限制
  1. 写操作频繁的场景:由于每次写操作都会复制整个底层数组,因此当写操作频繁时,CopyOnWriteArraySet 的性能会急剧下降。

  2. 大数据量场景:当集合中的数据量较大时,每次写操作都会复制整个底层数组,这将导致大量的内存占用和性能损耗。

  3. 实时性要求高的场景:由于CopyOnWriteArraySet 的写操作性能较差,因此不适合实时性要求高的场景。

  4. 迭代器使用场景:CopyOnWriteArraySet 的迭代器不支持快速失败(fail-fast)机制,因此不适合在迭代器使用过程中进行修改操作的场景。

📝 代码示例
import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetExample {
    public static void main(String[] args) {
        CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
        set.add("A");
        set.add("B");
        set.add("C");

        // 写操作
        set.add("D");

        // 读操作
        System.out.println(set.contains("A")); // 输出:true
    }
}
📝 最佳实践
  1. 合理选择集合类型:根据实际业务场景,选择合适的并发集合类型。

  2. 合理控制集合大小:避免在CopyOnWriteArraySet中使用大量数据,以降低内存占用和性能损耗。

  3. 避免在迭代器使用过程中进行修改操作:使用CopyOnWriteArraySet时,避免在迭代器使用过程中进行修改操作,以防止迭代器快速失败。

总之,CopyOnWriteArraySet 在读多写少,且写操作不频繁的场景下表现良好。但在其他场景下,应考虑使用其他并发集合类型。

CopyOnWriteArraySet 性能特点

CopyOnWriteArraySet 是 Java 并发集合框架中的一个类,它基于数组来实现集合的存储。下面是 CopyOnWriteArraySet 的性能特点:

特点描述
读操作性能非常快,因为读操作不会修改底层数组,直接返回数组副本即可。
写操作性能相对较慢,因为每次写操作(如 add、set、remove)都会创建一个新的数组,并将原数组中的元素复制到新数组中。
内存占用相对较高,因为每次写操作都会创建一个新的数组,导致内存占用增加。
线程安全线程安全,因为写操作会创建新的数组,不会影响其他线程的读操作。

适用场景

CopyOnWriteArraySet 适用于以下场景:

  • 读操作远多于写操作:由于读操作性能高,适用于读多写少的场景。
  • 数据量不大:由于写操作性能低,适用于数据量不大的场景。
  • 读操作需要保持数据一致性:由于线程安全,适用于需要保持数据一致性的场景。

与传统集合比较

集合CopyOnWriteArraySetArrayListLinkedListHashSet
读操作性能
写操作性能
线程安全
内存占用
适用场景读多写少、数据量不大、需要保持数据一致性需要频繁随机访问元素需要频繁插入和删除元素需要快速查找元素

线程安全机制

CopyOnWriteArraySet 的线程安全机制主要依赖于以下两点:

  1. 写操作创建新数组:每次写操作都会创建一个新的数组,并将原数组中的元素复制到新数组中,从而避免多个线程同时修改数组。
  2. 读操作返回数组副本:读操作返回的是原数组的副本,不会影响其他线程的读操作。

写操作性能影响

由于每次写操作都会创建一个新的数组,并将原数组中的元素复制到新数组中,因此写操作的性能相对较低。以下是一些写操作的性能影响:

  • 创建新数组:创建新数组需要消耗一定的时间和内存。
  • 复制元素:复制元素需要消耗一定的时间和内存。
  • 影响其他线程:写操作会阻塞其他线程的读操作,因为读操作需要等待写操作完成。

读操作性能分析

由于读操作不会修改底层数组,直接返回数组副本即可,因此读操作的性能非常高。以下是一些读操作的性能分析:

  • 返回数组副本:返回数组副本不需要消耗时间和内存。
  • 不影响其他线程:读操作不会影响其他线程的读操作和写操作。

内存占用分析

由于每次写操作都会创建一个新的数组,因此内存占用相对较高。以下是一些内存占用分析:

  • 创建新数组:每次写操作都会创建一个新的数组,导致内存占用增加。
  • 复制元素:复制元素需要消耗一定的时间和内存。

与其他并发集合比较

集合CopyOnWriteArraySetConcurrentHashMapCopyOnWriteArrayList
读操作性能
写操作性能
线程安全
内存占用
适用场景读多写少、数据量不大、需要保持数据一致性读多写多、数据量较大、需要保持数据一致性读多写多、数据量较大、需要保持数据一致性

实际应用案例

以下是一个使用 CopyOnWriteArraySet 的实际应用案例:

import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetExample {
    public static void main(String[] args) {
        CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
        set.add("Java");
        set.add("Python");
        set.add("C++");

        System.out.println("Set elements: " + set);
    }
}

优化建议

以下是一些针对 CopyOnWriteArraySet 的优化建议:

  • 减少写操作:尽量减少写操作,因为写操作性能较低。
  • 使用其他并发集合:如果读操作和写操作都很频繁,可以考虑使用其他并发集合,如 ConcurrentHashMap 或 CopyOnWriteArrayList。
  • 合理设置初始容量:合理设置初始容量可以减少数组扩容的次数,从而提高性能。

CSDN

博主分享

📥博主的人生感悟和目标

Java程序员廖志伟

📙经过多年在CSDN创作上千篇文章的经验积累,我已经拥有了不错的写作技巧。同时,我还与清华大学出版社签下了四本书籍的合约,并将陆续出版。

面试备战资料

八股文备战
场景描述链接
时间充裕(25万字)Java知识点大全(高频面试题)Java知识点大全
时间紧急(15万字)Java高级开发高频面试题Java高级开发高频面试题

理论知识专题(图文并茂,字数过万)

技术栈链接
RocketMQRocketMQ详解
KafkaKafka详解
RabbitMQRabbitMQ详解
MongoDBMongoDB详解
ElasticSearchElasticSearch详解
ZookeeperZookeeper详解
RedisRedis详解
MySQLMySQL详解
JVMJVM详解

集群部署(图文并茂,字数过万)

技术栈部署架构链接
MySQL使用Docker-Compose部署MySQL一主二从半同步复制高可用MHA集群Docker-Compose部署教程
Redis三主三从集群(三种方式部署/18个节点的Redis Cluster模式)三种部署方式教程
RocketMQDLedger高可用集群(9节点)部署指南
Nacos+Nginx集群+负载均衡(9节点)Docker部署方案
Kubernetes容器编排安装最全安装教程

开源项目分享

项目名称链接地址
高并发红包雨项目https://gitee.com/java_wxid/red-packet-rain
微服务技术集成demo项目https://gitee.com/java_wxid/java_wxid

管理经验

【公司管理与研发流程优化】针对研发流程、需求管理、沟通协作、文档建设、绩效考核等问题的综合解决方案:https://download.csdn.net/download/java_wxid/91148718

希望各位读者朋友能够多多支持!

现在时代变了,信息爆炸,酒香也怕巷子深,博主真的需要大家的帮助才能在这片海洋中继续发光发热,所以,赶紧动动你的小手,点波关注❤️,点波赞👍,点波收藏⭐,甚至点波评论✍️,都是对博主最好的支持和鼓励!

🔔如果您需要转载或者搬运这篇文章的话,非常欢迎您私信我哦~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值