Java并发基础:ConcurrentSkipListSet全面解析!

Java并发基础:ConcurrentSkipListSet全面解析! - 程序员古德

内容概要

ConcurrentSkipListSet类在多线程环境下,它能够轻松应对大量的插入、删除和查找操作,同时保持数据的完整性和一致性,其内部基于跳表数据结构的实现,确保了即使在处理大规模数据时,也能具有出色的性能表现。

核心概念

ConcurrentSkipListSet类实现了一个基于SkipList(跳表)算法的可排序的并发集合,SkipList是一种可以在对数预期时间内完成搜索、插入、删除等操作的数据结构,通过维护多个指向其他元素的“跳跃”链接来实现高效查找。

假如,有一个在线的电商系统,其中有一个功能是展示最热门的商品,这个“热门”的定义可以基于多种因素,比如销量、用户评分、浏览次数等,为了实时地反映这些热门商品,需要一个数据结构来存储和更新这些信息。

考虑到电商系统可能会有多个用户同时访问和修改热门商品列表,因此,就需要一个线程安全的集合来确保数据的完整性和一致性,同时,可能还需要根据某种指标(如销量)对商品进行排序,以便用户能够快速地看到最热门的商品。

使用ConcurrentSkipListSet可以很的解决这个问题,可以将商品对象作为元素添加到 ConcurrentSkipListSet 中,并根据销量或其他指标实现 Comparator 接口来对商品进行排序,由于 ConcurrentSkipListSet 是线程安全的,多个线程可以同时向集合中添加或删除商品,而不需要额外的同步措施。它还支持高效的并发访问,因此,即使有大量的用户同时访问热门商品列表,系统也能保持较高的响应速度。

ConcurrentSkipListSet 类通常用来解决两个核心问题:

  1. 并发访问:在多线程环境中,当多个线程需要同时读取或修改一个集合时,就需要一种线程安全的数据结构来确保数据的一致性和完整性,ConcurrentSkipListSet 提供了高效的并发访问能力,它使用了一种称为“跳表”(Skip List)的数据结构,这种数据结构能够在多线程环境下实现快速的查找、插入和删除操作,而不需要对整个集合进行锁定。
  2. 有序集合:除了并发访问外,ConcurrentSkipListSet 还解决了保持集合元素有序的问题,在许多应用场景中,需要一个能够按照某种顺序(自然顺序或自定义顺序)存储元素的集合,ConcurrentSkipListSet 实现了 SortedSet 接口,这意味着它可以根据元素的自然顺序或者通过构造函数提供的 Comparator 对象来对元素进行排序。

总结下来就是,ConcurrentSkipListSet 类主要用来解决在多线程环境下安全、高效地操作有序集合的问题,它结合了跳表的高效查找特性和并发控制机制,使得它成为处理需要高并发访问和有序性的数据集的理想选择,无论是在需要实时更新的排行榜系统、并发处理大量有序数据的服务器应用程序,还是在需要保持数据一致性和有序性的其他多线程场景中,ConcurrentSkipListSet 都能提供强大且有力的支持。

代码案例

下面是一个简单的Java代码,演示了如何使用ConcurrentSkipListSet类,这个示例中,将创建一个ConcurrentSkipListSet实例,并向其中添加一些整数,然后,将启动几个线程来并发地访问和修改这个集合,最后输出集合的内容,如下代码:

import java.util.concurrent.ConcurrentSkipListSet;  
  
public class ConcurrentSkipListSetExample {  
  
    public static void main(String[] args) throws InterruptedException {  
        // 创建一个ConcurrentSkipListSet实例,它将按照自然顺序对元素进行排序  
        ConcurrentSkipListSet<Integer> set = new ConcurrentSkipListSet<>();  
  
        // 向集合中添加一些初始元素  
        set.add(3);  
        set.add(1);  
        set.add(2);  
        System.out.println("Initial set: " + set); // 输出初始集合,应该是有序的:[1, 2, 3]  
  
        // 定义一个线程任务,用于向集合中添加元素  
        Runnable adderTask = () -> {  
            for (int i = 4; i <= 6; i++) {  
                set.add(i); // 尝试添加元素4, 5, 6  
                try {  
                    // 为了演示效果,让线程稍微休眠一下  
                    Thread.sleep(100);  
                } catch (InterruptedException e) {  
                    Thread.currentThread().interrupt();  
                }  
            }  
        };  
  
        // 定义一个线程任务,用于从集合中删除元素  
        Runnable removerTask = () -> {  
            for (int i = 1; i <= 3; i++) {  
                set.remove(i); // 尝试删除元素1, 2, 3  
                try {  
                    // 为了演示效果,让线程稍微休眠一下  
                    Thread.sleep(150);  
                } catch (InterruptedException e) {  
                    Thread.currentThread().interrupt();  
                }  
            }  
        };  
  
        // 启动线程来并发地修改集合  
        Thread adderThread = new Thread(adderTask);  
        Thread removerThread = new Thread(removerTask);  
        adderThread.start();  
        removerThread.start();  
  
        // 等待线程执行完成  
        adderThread.join();  
        removerThread.join();  
  
        // 输出最终的集合内容  
        System.out.println("Final set: " + set); // 输出结果取决于线程的执行顺序,但集合仍然是有序的  
    }  
}

在上面代码中,创建了一个ConcurrentSkipListSet实例,并初始化了三个元素(1, 2, 3),然后,定义了两个Runnable任务:一个用于向集合中添加元素(4, 5, 6),另一个用于从集合中删除元素(1, 2, 3),这两个任务将在不同的线程中并发执行。

核心API

ConcurrentSkipListSet 类实现了 SortedSet 接口,内部基于 Skip List(跳表)数据结构,并提供了高效的并发访问,这个类能够保证元素的有序性,并且允许并发修改。以下是 ConcurrentSkipListSet 类中一些重要方法的含义:

1、构造方法

  • ConcurrentSkipListSet(): 创建一个新的空集合,根据元素的自然排序进行排序。
  • ConcurrentSkipListSet(Comparator<? super E> comparator): 创建一个新的空集合,根据提供的比较器进行排序。

2、添加元素

  • boolean add(E e): 将指定的元素插入此集合(如果尚未存在)。
  • boolean addAll(Collection<? extends E> c): 将指定集合中的所有元素插入此集合。

3、删除元素

  • boolean remove(Object o): 从此集合中移除指定元素的单个实例(如果存在)。
  • boolean removeAll(Collection<?> c): 移除此集合中那些也包含在指定集合中的所有元素。
  • void clear(): 移除此集合中的所有元素。

4、查询元素

  • boolean contains(Object o): 如果此集合包含指定的元素,则返回 true
  • boolean containsAll(Collection<?> c): 如果此集合包含指定集合中的所有元素,则返回 true

5、获取视图

  • Iterator<E> iterator(): 返回在此集合的元素上进行迭代的迭代器。
  • NavigableSet<E> descendingSet(): 返回此集合中所有元素的逆序视图。
  • Iterator<E> descendingIterator(): 返回在此集合的元素上以逆序进行迭代的迭代器。

6、获取子集或超集

  • NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive): 返回此集合的部分视图,其元素范围从 fromElementtoElement
  • NavigableSet<E> headSet(E toElement, boolean inclusive): 返回此集合的部分视图,其元素都小于(或等于,如果 inclusivetruetoElement
  • NavigableSet<E> tailSet(E fromElement, boolean inclusive): 返回此集合的部分视图,其元素都大于(或等于,如果 inclusivetruefromElement

7、其它核心方法

  • E first(): 返回当前具有最小元素的视图关系的第一个(最小)元素。
  • E last(): 返回当前具有最大元素的视图关系的最后一个(最大)元素。
  • E lower(E e): 返回此集合中小于指定元素的最大元素;如果不存在这样的元素,则返回 null
  • E floor(E e): 返回此集合中小于等于指定元素的最大元素;如果不存在这样的元素,则返回 null
  • E ceiling(E e): 返回此集合中大于等于指定元素的最小元素;如果不存在这样的元素,则返回 null
  • E higher(E e): 返回此集合中大于指定元素的最小元素;如果不存在这样的元素,则返回 null
  • int size(): 返回此集合中的元素数量(此操作可能很耗时,因为它可能要遍历整个集合)。
  • boolean isEmpty(): 如果此集合不包含任何元素,则返回 true

注意:由于 ConcurrentSkipListSet 是为并发设计的,因此上述方法中的大多数都提供了线程安全性的保证,可以在多线程环境中安全使用,然而,size() 方法可能需要遍历整个数据结构来确定元素数量,因此在并发环境中使用时可能不是很高效。

核心总结

Java并发基础:ConcurrentSkipListSet全面解析! - 程序员古德

ConcurrentSkipListSet类是一个强大的并发有序集合实现,它提供了高效的插入、删除和查找操作,其优点在于出色的并发性能,能够在多线程环境下保持数据的一致性和有序性,适用于需要高并发访问和修改的场景,并且,由于它基于跳表数据结构,因此在数据量较大时仍能保持良好的性能。

ConcurrentSkipListSet类也存在一些缺点,比如,相比于非并发集合,它的内存消耗较大,这就导致了在某些极端情况下,跳表的维护可能会带来额外的开销。

在技术方案选择时,如果应用需要处理大量并发读写操作,并且对数据的有序性有较高要求,那么推荐使用ConcurrentSkipListSet

END!
END!
END!

往期回顾

精品文章

Java并发基础:SynchronousQueue全面解析!

Java并发基础:ConcurrentLinkedQueue全面解析!

Java并发基础:Exchanger全面解析!

Java并发基础:ConcurrentLinkedDeque全面解析!

Java并发基础:PriorityBlockingQueue全面解析!

精彩视频

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于微信小程序的健身房私教预约系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

类的构造方法

在类中&#xff0c;出成员方法外&#xff0c;还存在一种特殊类型的方法&#xff0c;那就是构造方法。构造方法是一个与类同名的方法&#xff0c;对象的创建就是通过构造方法完成的。每个类实例化一个对象时&#xff0c;类都会自动调用构造方法。 构造方法的特点&#xff1a; 构…

文件上传漏洞--Upload-labs--Pass01--前端绕过

一、前端绕过原理 通俗解释&#xff0c;我们将写有恶意代码的php后缀文件上传到网页&#xff0c;网页中的javascript代码会先对文件的后缀名进行检测&#xff0c;若检测到上传文件的后缀名为非法&#xff0c;则会进行alert警告。若想上传php后缀的文件&#xff0c;就要想办法对…

Acwing---877. 扩展欧几里得算法

扩展欧几里得算法 1.题目2.基本思想3.代码实现 1.题目 给定 n n n 对正整数 a i ai ai, b i bi bi&#xff0c;对于每对数&#xff0c;求出一组 x i xi xi, y i yi yi&#xff0c;使其满足 a i x i b i y i g c d ( a i , b i ) aixibiyigcd(ai,bi) aixibiyigcd(ai,bi)…

K8s进阶之路-安装部署K8s

参考&#xff1a;&#xff08;部署过程参考的下面红色字体文档链接就可以&#xff0c;步骤很详细&#xff0c;重点部分在下面做了标注&#xff09; 安装部署K8S集群文档&#xff1a; 使用kubeadm方式搭建K8S集群 GitBook 本机&#xff1a; master&#xff1a;10.0.0.13 maste…

pytorch 实现线性回归(深度学习)

一 查看原始函数 初始化 %matplotlib inline import random import torch from d2l import torch as d2l 1.1 生成原始数据 def synthetic_data(w, b, num_examples):x torch.normal(0, 1, (num_examples, len(w)))y torch.matmul(x, w) bprint(x:, x)print(y:, y)y tor…

JavaWeb-JDBC-API详解

一、JDBC介绍 二、JDBC 快速入门 package com.itheima.jdbc;import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement;public class JDCBDemo {public static void main(String[] args) throws Exception {//1、注册驱动Class.forName("co…

django中事务和锁

目录 一&#xff1a;事务&#xff08;Transactions&#xff09; 二&#xff1a;锁 在Django中&#xff0c;事务和锁是数据库操作中的两个重要概念&#xff0c;它们用于确保数据的完整性和一致性。下面我将分别解释这两个概念在Django中的应用。 一&#xff1a;事务&#xff…

Code Composer Studio (CCS) - Breakpoint (断点)

Code Composer Studio [CCS] - Breakpoint [断点] 1. BreakpointReferences 1. Breakpoint 选中断点右键 -> Breakpoint Properties… Skip Count&#xff1a;跳过断点总数&#xff0c;在断点执行之前设置总数 Current Count&#xff1a;当前跳过断电累计值 References […

Ubuntu学习笔记-Ubuntu搭建禅道开源版及基本使用

文章目录 概述一、Ubuntu中安装1.1 复制下载安装包路径1.2 将安装包解压到ubuntu中1.3 启动服务1.4 设置开机自启动 二、禅道服务基本操作2.1 启动&#xff0c;停止&#xff0c;重启&#xff0c;查看服务状态2.2 开放端口2.3 访问和登录禅道 卜相机关 卜三命、相万生&#xff0…

第13章 网络 Page738~741 13.8.3 TCP/UDP简述

libcurl是C语言写成的网络编程工具库&#xff0c;asio是C写的网络编程的基础类型库 libcurl只用于客户端&#xff0c;asio既可以写客户端&#xff0c;也可以写服务端 libcurl实现了HTTP\FTP等应用层协议&#xff0c;但asio却只实现了传输层TCP/UDP等协议。 在学习http时介绍…

CSS概述 | CSS的引入方式 | 选择器

文章目录 1.CSS概述2.CSS的引入方式2.1.内部样式表2.2.行内样式表2.3.外部样式表 3.选择器 1.CSS概述 CSS&#xff0c;全称Cascading Style Sheets&#xff08;层叠样式表&#xff09;&#xff0c;是一种用来设置HTML&#xff08;或XML等&#xff09;文档样式的语言。CSS的主要…

Code Composer Studio (CCS) - Current and Local Revision

Code Composer Studio [CCS] - Current and Local Revision References 鼠标放在文件内的任意位置&#xff0c;鼠标右键 -> Compare With -> Local History -> Revision Time. References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

vue-路由(六)

阅读文章你可以收获什么&#xff1f; 1 明白什么是单页应用 2 知道vue中的路由是什么 3 知道如何使用vueRouter这个路由插件 4 知道如何如何封装路由组件 5 知道vue中的声明式导航router-link的用法 6 知道vue中的编程式导航的使用 7 知道声明式导航和编程式导航式如何传…

【数据结构】18 二叉搜索树(查找,插入,删除)

定义 二叉搜索树也叫二叉排序树或者二叉查找树。它是一种对排序和查找都很有用的特殊二叉树。 一个二叉搜索树可以为空&#xff0c;如果它不为空&#xff0c;它将满足以下性质&#xff1a; 非空左子树的所有键值小于其根节点的键值非空右子树的所有键值都大于其根结点的键值左…

Rust 学习笔记 - 注释全解

前言 和其他编程语言一样&#xff0c;Rust 也提供了代码注释的功能&#xff0c;注释用于解释代码的作用和目的&#xff0c;帮助开发者理解代码的行为&#xff0c;编译器在编译时会忽略它们。 单行注释 单行注释以两个斜杠 (//) 开始&#xff0c;只影响它们后面直到行末的内容…

Java面向对象三大特征之封装

封装的作用和含义&#xff1a; 程序的设计要追求“高内聚&#xff0c;低耦合”。高内聚就是类的内部数据操作细节自己完成&#xff0c;不允许外部干涉&#xff1b;低耦合是仅暴露少量的方法给外部使用&#xff0c;尽量方便外部调用。 编程中封装的具体优点&#xff1a; 提高代…

Days 33 ElfBoard 固定CPU频率

ELF 1开发板选用的是主频800MHz NXP的i.MX6ULL处理器。根据实际的应用场景&#xff0c;如果需要降低CPU功耗&#xff0c;其中一种方法可以将CPU频率固定为节能模式&#xff0c;下面以这款开发板为例给小伙伴们介绍一下固定CPU频率的方法。 先来介绍一下与CPU频率相关的命令&…

关于umi ui图标未显示问题

使用ant design pro 时&#xff0c;安装了umi ui &#xff0c;安装命令&#xff1a; yarn add umijs/preset-ui -D但是启动项目后&#xff0c;发现没有显示umi ui的图标 找了许多解决方案&#xff0c;发现 umi的版本问题&#xff0c;由于我使用的ant design pro官网最新版本&a…

Quantitative Analysis: PIM Chip Demands for LLAMA-7B inference

1 Architecture 如果将LLAMA-7B模型参数量化为4bit&#xff0c;则存储模型参数需要3.3GB。那么&#xff0c;至少PIM chip 的存储至少要4GB。 AiM单个bank为32MB&#xff0c;单个die 512MB&#xff0c;至少需要8个die的芯片。8个die集成在一个芯片上。 提供816bank级别的访存带…