Java基础 - 09 Set之linkedHashSet , CopyOnWriteArraySet

LinkedHashSet和CopyOnWriteArraySet都是Java集合框架提供的特殊集合类,他们在特定场景下有不同的用途和特点。

LinkedHashSet是Java集合框架中的一种实现类,它继承自HashSet并且保持插入顺序。它使用哈希表来存储元素,并使用链表来维护插入顺序。由于使用哈希表,LinkedHashSet提供了常数时间的复杂度(O(1))来执行插入、删除和查找操作。同时,由于使用链表来维护插入顺序,LinkedHashSet可以按照元素的插入顺序进行迭代。因此,LinkedHashSet适用于需要保持插入顺序并且需要高效的插入、删除和查找操作的场景。

CopyOnWriteArraySet是Java并发包中的一种线程安全的Set实现。它实现了Set接口,并且使用了CopyOnWriteArrayList作为内部数据结构。CopyOnWriteArraySet通过在每次修改时创建一个新的副本来实现线程安全性,因此在并发修改操作时不会出现ConcurrentModificationException异常。它适用于读操作频繁、写操作较少的场景,因为每次修改都会创建一个新的副本,可能会带来一定的内存开销。由于CopyOnWriteArraySet是无序的,它不会维护插入顺序。因此,如果需要保持元素的插入顺序,应该使用LinkedHashSet。

LinkedHashSet

LinkedHashSet是一个基于哈希表链表实现的有序集合。它继承自HashSet,并且保留了元素插入的顺序。LinkedHashSet通过哈希表快速访问元素,同时使用链表维护元素的顺序。这使得LinkedHashSet在需要保持元素顺序的情况下更加适用。

在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {LinkedHashSet<String> set = new LinkedHashSet<>();// 添加元素set.add("apple");set.add("banana");set.add("orange");// 迭代元素,按照插入顺序输出for (String fruit : set) {System.out.println(fruit);}}

源码:

public class LinkedHashSet<E>extends HashSet<E>implements Set<E>, Cloneable, java.io.Serializable {/*** 构造一个带默认初始容量 (16) 和加载因子 (0.75) 的新空链接哈希 set。*/public LinkedHashSet() {super(16, .75f, true);}/***  构造一个与指定 collection 中的元素相同的新链接哈希 set。*/public LinkedHashSet(Collection<? extends E> c) {super(Math.max(2*c.size(), 11), .75f, true);addAll(c);}/*** 构造一个带指定初始容量和默认加载因子 (0.75) 的新空链接哈希 set。*/public LinkedHashSet(int initialCapacity) {super(initialCapacity, .75f, true);}/*** 构造一个带有指定初始容量和加载因子的新空链接哈希 set。*/public LinkedHashSet(int initialCapacity, float loadFactor) {super(initialCapacity, loadFactor, true);}
}

以下是一些LinkedHashSet的特点和用途:

  • LinkedHashSet保留了元素插入的顺序,因此可以按照插入顺序进行迭代
  • LinkedHashSet线程不安全的,不适用于多线程环境。
  • LinkedHashSet具有HashSet的高效查找特性,同时还可以保持元素的顺序。
  • LinkedHashSet的插入、删除和查找操作具有常数时间复杂度。

CopyOnWriteArraySet

CopyOnWriteArraySet是一个线程安全的集合类,它实现了Set接口,并且内部使用了Copy-On-Write技术。Copy-On-Write是一种并发策略,它在写操作时创建并复制整个集合,这样读操作不会受到写操作的影响。因此,CopyOnWriteArraySet非常适合用于读多写少的场景。

在这里插入图片描述

以下是一些CopyOnWriteArraySet的特点和用途:

  • CopyOnWriteArraySet是线程安全的,适用于多线程环境。
  • CopyOnWriteArraySet的迭代操作不需要加锁,并且不会抛出ConcurrentModificationException异常。
  • CopyOnWriteArraySet的写操作会复制整个集合,因此在写操作频繁的情况下,性能可能较低。
  • CopyOnWriteArraySet的读操作具有较低的性能开销
    在这里插入图片描述
    内部方法介绍
  • add(E e): 向集合中添加指定元素。该方法会创建一个新的数组,并将指定元素添加到新数组中
  • remove(Object o): 从集合中移除指定元素。该方法会创建一个新的数组,并将除指定元素之外的所有元素添加到新数组中。
  • contains(Object o): 判断集合中是否包含指定元素。该方法会遍历内部的数组,判断是否有相等的元素
  • isEmpty(): 判断集合是否为空。该方法会判断内部的数组是否为空。
  • size(): 返回集合的大小,即元素的个数。该方法会返回内部数组的长度。
  • iterator(): 返回一个迭代器**,用于遍历集合中的元素**。该方法返回的迭代器是通过拷贝内部数组创建的,因此不会受到集合修改的影响。
  • toArray(): 将集合中的元素转换为数组,并返回该数组。该方法会创建一个新的数组,并将集合中的元素复制到新数组中。

两者直接的区别

CopyOnWriteArraySet

CopyOnWriteArraySet适用于读多写少的并发场景。它通过使用Copy-On-Write技术,在写操作时创建并复制整个集合,这样读操作不会受到写操作的影响。这使得CopyOnWriteArraySet在多线程环境下具有较好的安全性,读操作不需要加锁,并且不会抛出ConcurrentModificationException异常。因此,当需要在多线程环境下进行读操作较多的场景时,可以使用CopyOnWriteArraySet。

import java.util.concurrent.CopyOnWriteArraySet;public class CopyOnWriteArraySetExample {public static void main(String[] args) {CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();// 添加元素set.add("apple");set.add("banana");set.add("cherry");// 遍历元素for (String element : set) {System.out.println(element);}// 删除元素set.remove("banana");// 判断元素是否存在boolean contains = set.contains("cherry");System.out.println("Contains 'cherry': " + contains);// 获取集合大小int size = set.size();System.out.println("Size: " + size);}
}

LinkedHashSet

LinkedHashSet是HashSet的一个子类,它维护了一个双向链表来保持元素的插入顺序。LinkedHashSet适用于需要保持元素插入顺序的场景。它提供了HashSet的高性能查找和插入操作,并且使用链表来保持插入顺序。因此,当需要在保持插入顺序的同时进行高效的查找和插入操作时,可以使用LinkedHashSet。

import java.util.LinkedHashSet;public class LinkedHashSetExample {public static void main(String[] args) {LinkedHashSet<String> set = new LinkedHashSet<>();// 添加元素set.add("apple");set.add("banana");set.add("cherry");// 遍历元素for (String element : set) {System.out.println(element);}// 删除元素set.remove("banana");// 判断元素是否存在boolean contains = set.contains("cherry");System.out.println("Contains 'cherry': " + contains);// 获取集合大小int size = set.size();System.out.println("Size: " + size);}
}

在多线程环境下,CopyOnWriteArraySet比LinkedHashSet具有更好的安全性。CopyOnWriteArraySet的读操作不需要加锁,并且不会抛出ConcurrentModificationException异常。而LinkedHashSet在多线程环境下需要使用外部同步机制来确保线程安全。例如,可以使用Collections.synchronizedSet()。

创建一个多线程环境下使用LinkedHashSet的示例

public class LinkedHashSetThreadSafetyExample {public static void main(String[] args) {Set<String> set = Collections.synchronizedSet(new LinkedHashSet<>());// 创建多个线程来同时对set进行操作Thread thread1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {set.add("Thread 1 - Element " + i);}});Thread thread2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {set.add("Thread 2 - Element " + i);}});// 启动线程thread1.start();thread2.start();try {// 等待线程执行完毕thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}// 输出set的元素数量System.out.println("Set size: " + set.size());}
}

在上述代码中,我们创建了一个多线程环境下使用LinkedHashSet的示例。首先,我们使用Collections.synchronizedSet()方法创建了一个线程安全的Set,即使用外部同步机制来确保线程安全。然后,我们创建了两个线程thread1和thread2,分别向set中添加1000个元素。最后,我们使用thread1.join()和thread2.join()方法等待两个线程执行完毕,然后输出set的元素数量。

使用CopyOnWriteArraySet类来实现多线程安全的Set。

import java.util.concurrent.CopyOnWriteArraySet;public class CopyOnWriteArraySetThreadSafetyExample {public static void main(String[] args) {CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();// 创建多个线程来同时对set进行操作Thread thread1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {set.add("Thread 1 - Element " + i);}});Thread thread2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {set.add("Thread 2 - Element " + i);}});// 启动线程thread1.start();thread2.start();try {// 等待线程执行完毕thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}// 输出set的元素数量System.out.println("Set size: " + set.size());}
}

在上述代码中,我们使用CopyOnWriteArraySet类来实现多线程安全的Set。CopyOnWriteArraySet是一个线程安全的Set实现,通过在每次修改时创建一个新的副本来实现线程安全性。这意味着在并发修改操作时,不会发生ConcurrentModificationException异常。

我们创建了一个CopyOnWriteArraySet对象,然后创建了两个线程thread1和thread2,分别向set中添加1000个元素。最后,我们使用thread1.join()和thread2.join()方法等待两个线程执行完毕,然后输出set的元素数量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/642934.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

centos查看1分钟内修改过的文件

linux查看1分钟内修改过的文件 find / -name ‘.’ -mmin -1 查询1分钟内修改过的日志 查询根目录下以log结尾&#xff0c;1分钟内修改过的文件 find / -name ‘*.log’ -mmin -1 下面的命令是查询当前目录下所有的文件&#xff0c;并且在30分钟内修改过的文件 这个可以根…

前端JavaScript篇之Javscript数组的常用方法有哪些?JavaScript判断数组的方式有哪些?

目录 Javscript数组的常用方法有哪些&#xff1f;JavaScript判断数组的方式有哪些&#xff1f;1. Array.isArray() 方法&#xff1a;2. instanceof 操作符&#xff1a;3. Object.prototype.toString.call() 方法&#xff1a;4. Array.from() 方法&#xff1a; Javscript数组的常…

Git学习笔记(第3章):Git常用命令

目录 3.1 设置用户签名 3.2 初始化本地库 3.3 查看本地库状态 3.4 添加暂存区 3.5 提交本地库 3.6 历史版本 3.7 修改文件 3.8 版本穿梭 小结 命令 作用 git config --global user.name 用户名 设置用户签名 git config --global user.email 邮箱 设置用户签名 …

Java如何优雅地判断对象是否为空

点击下载《Java如何优雅地判断对象是否为空》 1. 前言 在实际项目中&#xff0c;我们经常需要对各种变量或对象进行判空校验。这是因为&#xff0c;如果不进行判空校验&#xff0c;当遇到空值时&#xff0c;可能会导致程序出现NullPointerException异常。这是一种常见的运行时…

【INTEL(ALTERA)】为什么 Nios® V/g 处理器无法从指令紧耦合内存 (TCM) 启动?

说明 由于英特尔 Quartus Prime Pro Edition 软件版本 23.3 对Nios V/g 处理器的限制&#xff0c;Nios V/g 处理器无法直接从内存初始化的指令 TCM 启动。 造成这个问题的主要原因是指令中药只能作为指令存储器访问&#xff08;不支持作为指令和数据存储器&#xff09;。因此…

全国各城市绿地及绿化面积数据,shp/excel格式,2020-2022年

基本信息. 数据名称: 全国各城市绿地及绿化面积数据 数据格式: Shp、excel 数据时间: 2020-2022年 数据几何类型: 面 数据坐标系: WGS84 数据来源&#xff1a;网络公开数据 数据字段&#xff1a; 序号字段名称字段说明1province省份名称2city城市名称4city_dm城市…

2401llvm,clang语法树简介

原文 ClangAST简介 幻灯片 介绍 Clang的AST与其他一些编译器生成的AST不同,因为它与编写的C代码和C标准类似.如,在AST中,按非简化形式提供括号式和编译时常量. 这使得Clang的AST非常适合重构. 可通过生成的Doxygen获得所有ClangAST节点的文档.搜索引擎也会索引doxygen的在…

Servlet对象

ServletConfig对象 是什么 ServletConfig是javax.servlet.包下的一个接口&#xff0c;ServletConfig它是Servlet的一个配置对象&#xff1b; ServletConfig是由tomcat容器创建&#xff0c;通过init方法传入给Servlet&#xff1b; ServletConfig对象如何获取? 在GenericServle…

SpringBoot连接mysql数据库相关配置(druid连接池)

一、引入mysql8依赖 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.23</version></dependency><dependency><groupId>com.alibaba</groupId><artifa…

【python】python实现代码雨【附源码】

欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 一、效果图&#xff1a; 二、准备工作 &#xff08;1)、导入必要的模块&#xff1a; 代码首先导入了需要使用的模块&#xff1a;requests、lxml和csv。 import requests from lxml import etree import csv 如果出现模…

Linux大老都是怎么记住这么多命令的?

今天给大家带来的是面试/实际工作中经常用到的Linux相关操作命令: 一. vi/vim编辑器 ---->文本编辑器 作用&#xff1a;创建文件&#xff0c;编辑文件&#xff0c;查看文件 格式&#xff1a;vi/vim 文件的名字 解析&#xff1a;如果该文件不存在&#xff0c;vi就会创建该…

logback配置xml日志文件(保姆级教程)

前言 这是个啥,这就是个控制日志输出格式、控制日志输出位置、控制日志输出环境、控制日志输出级别的玩意、控制忽略输出的日志就这些功能,没有什么很复杂的东西,废话不说多了。 配置介绍 configuration <configuration scan="true" scanPeriod="10 s…

外包干了一个月,技术退步明显。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入南京某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

【QML COOK】- 012-在QML中使用OpenGL渲染

本文是参照了两个文章编写的。 一是QML的例子&#xff1a;Scene Graph - OpenGL Under QML | Qt Quick 6.6.1 二是关于SceneGraph的介绍&#xff1a;Qt Quick Scene Graph | Qt Quick 6.2.11 这里我提取一下重点方便大家理解。 一个QML程序只能用一种计算机图形接口。不能有…

基于SpringBoot Vue美食网站系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

测试工程师必看!测试用例设计全解析,让你彻底掌握

测试工程师在入行时&#xff0c;都会接触到一个名词——测试用例&#xff0c;都知道测试用例是干什么用的&#xff0c;提到设计测试用例的方法&#xff0c;大部分测试工程师都会侃侃而谈&#xff1a;等价类法、边界值法、判定表法、正交分解法……这些方法说起来都如数家珍&…

MySQL的MVCC

MVCC&#xff08;多版本并发控制&#xff09;multiversion concurrency control 读读并发&#xff1a;可以并发 读写并发&#xff08;innoDB&#xff09;&#xff1a;MVCC机制解决 写写&#xff1a;互斥 快照读&#xff1a;不加锁的简单select属于快照读&#xff0c;即不加…

揭秘大数据时代的内存数据存储、数据缓存:redis缓存框架!

介绍&#xff1a;Redis 是一个开源的、基于内存的数据存储系统&#xff0c;它也可以持久化数据到硬盘上。Redis 以其高性能、高可靠性和丰富的数据结构支持而著称&#xff0c;在现代应用程序中被广泛用作数据库、缓存和消息中间件。 主要特点&#xff1a; 键值存储&#xff1a;…

Unity工程没有创建.sln文件,导致打开C#文件无法打开解决方案

最近又开始折腾些Unity的小项目&#xff0c;重新遇到一些常见的小问题 点击报错文件 却没有打开文件 于是查看了下打开Window->Package Manager 选择Unity Registry 搜索Visual Studio Editor&#xff0c;发现并没有安装 同理&#xff0c;也可以安装VSCode的插件 问题解决了…

JVM多线程读写和锁

文章目录 1 原子性2 可见性3 有序性4 CAS5 synchronized 优化5.1 轻量级锁5.2 锁膨胀5.3 自旋5.4 偏向锁5.5 其他优化 1 原子性 问题:两个线程对初始值为 0 的静态变量 i 一个做自增&#xff0c;一个做自减&#xff0c;各做 5000 次&#xff0c;结果是 0 吗&#xff1f; i产生…