Java 入门指南:Java 并发编程 —— 并发容器 ConcurrentSkipListSet

news2024/11/15 21:21:10

SkipList

SkipList(跳表)是一种有序链表加多级索引数据结构,基于有序的单链表,类似于平衡二叉树,但其查找、插入和删除操作的时间复杂度都是 O(logN),并且不需要进行旋转平衡等复杂操作。

跳表利用二分查找的思想,通过添加多层索引来加速查找的过程,因此可以有效地支持高效的插入、删除和查找操作。

Redis 中的 有序集合 sorted set 就是用跳表实现的

实现原理

跳表的基本结构包含多个层级,每个层级都是一个有序链表。最底层是最完整的有序链表,每个节点都包含一个值和一个指向下一个节点的指针。其他层级通过连接部分节点来实现跨级访问,即跳跃查找

构建跳表
  • 建立一级索引

    为了提高查找效率,使用 二分查找 的思想,对有序链表建立一级“索引”。 每两个节点提取一个节点到索引层。 索引层中的每个节点 都包含两个指针,一个 next 指针,指向下一个节点,一个 down 指针,指向下一级节点。

  • 建立二级索引

    与建立一级索引的方式类似,在第一级索引的基础上,每两个节点抽出一个节点到第二级索引

![[SkipList.png]]

通过建立索引的方式,对于数据量越大的有序链表,通过建立多级索引,查找效率提升会非常明显。

基本操作

跳表的插入、删除和查找操作都从最顶层开始,逐层向下进行。

查找操作从最顶层的头节点开始,根据节点值的大小与目标值进行比较:

  • 如果小于目标值,继续移动到当前层级的下一个节点

  • 如果大于目标值,则将层级降低到下一层级,继续比较。直到找到目标值或者无法继续降低层级,查找结束。

插入和删除操作类似于查找操作,也是从最顶层开始,按照相同的方式进行查找,找到对应位置后进行插入或删除节点,并调整层级索引。

优点

跳表的优势在于简单、高效,并且不需要进行复杂的平衡操作。其时间复杂度与平衡二叉树相当,但实现起来更简单。然而,跳表相对于平衡二叉树的空间复杂度稍高,因为需要维护多层索引。

跳表在实际应用中广泛用于需要高效的有序查找的场景,特别是在并发环境下,因为跳表的结构对并发操作友好,可以提供较好的并发性能。

ConcurrentSkipListSet

ConcurrentSkipListSet 是 Java 中的一个线程安全集合类,实现了SortedSet 接口,并基于跳表数据结构进行实现。它支持高效的插入、删除和查找操作,并提供了强一致性、线程安全的操作保证。

ConcurrentSkipListSet 底层基于跳表,每个节点包含一个值多个指向下一个节点的指针

在插入、删除、查找元素时,ConcurrentSkipListSet 会从节点的最高层级开始查找,并逐层降低层级,直到找到对应的节点或无法继续降低层级。

ConcurrentSkipListSet (Java SE 11 & JDK 11 ) (oracle.com)

应用场景

  • 高并发访问的有序集合:在需要频繁插入、删除和查找有序元素的多线程环境中,ConcurrentSkipListSet 是一个理想的选择。
  • 排行榜系统:如电商系统中的热门商品排行榜,可以根据销量、评分等因素实时更新排名。
  • 任务调度系统:根据任务的优先级进行排序,并允许动态添加或取消任务。

特点

ConcurrentSkipListSet 的特性如下:

  1. 线程安全:ConcurrentSkipListSet 支持多线程的并发访问,保证了线程安全性。

  2. 有序集合:ConcurrentSkipListSet 继承了 SortedSet 接口,保证了有序的元素集合。

  3. 可能存在重复元素:ConcurrentSkipListSet 可以存在相同的元素,因此在插入元素时需要注意。

  4. 高效的插入、删除和查找操作:ConcurrentSkipListSet 采用跳表的数据结构,在高度平衡与高效性之间取得了一个良好的平衡,具有较高的速度。

常用方法

  1. add(E e):将指定的元素添加到集合中,如果已存在则不进行添加。

  2. remove(Object o):从集合中移除指定的元素,如果不存在则不进行移除。

  3. contains(Object o):判断集合是否包含指定的元素,返回布尔值。

  4. isEmpty():判断集合是否为空,如果为空则返回true,否则返回false。

  5. size():返回集合中元素的数量。

  6. first():获取集合中的第一个元素。

  7. last():获取集合中的最后一个元素。

  8. headSet(E toElement):返回一个子集合,包含所有小于给定元素的元素。

  9. tailSet(E fromElement):返回一个子集合,包含所有大于等于给定元素的元素。

  10. subSet(E fromElement, E toElement):返回一个子集合,包含所有在给定范围之内的元素。

  11. iterator():返回集合的迭代器,用于遍历集合的元素。

构造方法

  1. 创建一个空的 ConcurrentSkipListSet,使用元素的自然顺序进行排序。
ConcurrentSkipSet()
  1. 创建一个空的 ConcurrentSkipListSet,使用指定的比较器对元素进行排序。
ConcurrentSkipListSet(Comparator<? super E> comparator)
  1. 创建一个包含指定集合的元素的 ConcurrentSkipListSet
ConcurrentSkipListSet(Collection<? extends E> collection)
  1. 创建一个包含指定排序集合的元素的 ConcurrentSkipListSet
ConcurrentSkipListSet(SortedSet<E> set)

使用示例

以下是一个使用 ConcurrentSkipListSet 基本操作的简单示例

import java.util.concurrent.ConcurrentSkipListSet;

public class ConcurrentSkipListSetExample {

    public static void main(String[] args) {
        // 创建一个 ConcurrentSkipListSet 实例
        ConcurrentSkipListSet<Integer> skipListSet = new ConcurrentSkipListSet<>();

        // 插入元素
        skipListSet.add(3);
        skipListSet.add(1);
        skipListSet.add(4);
        skipListSet.add(2);

        // 输出集合
        System.out.println("Initial Set: " + skipListSet);

        // 判断是否存在元素
        boolean contains = skipListSet.contains(5);
        System.out.println("Contains '5': " + contains);

        // 添加重复元素
        boolean added = skipListSet.add(1);
        System.out.println("Added '1' again: " + added);

        // 删除元素
        boolean removed = skipListSet.remove(3);
        System.out.println("Removed '3': " + removed);

        // 使用 headSet 和 tailSet
        System.out.println("Head Set (up to 3): " + skipListSet.headSet(3));
        System.out.println("Tail Set (from 3): " + skipListSet.tailSet(3));

        // 使用 subSet
        System.out.println("Sub Set (from 2 to 4): " + skipListSet.subSet(2, 4));

        // 遍历所有元素
        skipListSet.forEach(item -> System.out.println("Item: " + item));

        // 清空集合
        skipListSet.clear();
    }
}

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

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

相关文章

【滑动窗口】将 x 减到 0 的最小操作数

将 x 减到 0 的最小操作数 将 x 减到 0 的最小操作数题目思路讲解代码书写 将 x 减到 0 的最小操作数 题目 题目链接: 将 x 减到 0 的最小操作数 思路讲解 按照题目的思路去做这一题是非常恶心的, 因此我们采用正难则反思路. 将问题转换为: 求中间某一个最长的数组长度, 使…

mybatis搭建,参数传递,增删改查事务管理

1.mybatis概述 原是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation 迁移到了 Google Code&#xff0c;随着开发团队转投Google Code 旗下&#xff0c; iBatis3.x正式更名为MyBatis。 MyBatis 是一款优秀的持久层框架。 框架就是对技术的封装&am…

Spring源码之reader、scanner

目录 1.Spring的整体启动流程 2.reader 3.Scanner ApplicationContext的三种加载应用上下文的方式&#xff08;创建Spring容器&#xff09;&#xff1a; AnnotationConfigApplicationContextClassPathXmlApplicationContextFileSystemXmlApplicationContext 1.Spring的整体…

SprinBoot+Vue阅读交流微信小程序的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue3.6 uniapp代码 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平…

观测云核心技术解密:eBPF Tracing 实现原理

前言 eBPF 是一种强大的内核技术&#xff0c;允许在内核中安全地执行自定义代码。通过 eBPF&#xff0c;开发者可以在不修改内核源码的情况下&#xff0c;对内核功能进行扩展和监控。eBPF Tracing 利用这一技术&#xff0c;对系统调用、内核函数等进行跟踪&#xff0c;从而实现…

X86架构(六)——移位指令与无条件转移指令

移位指令 shr 逻辑右移 逻辑右移指令会将操作数连续地向右移动指定的次数&#xff0c;移出的比特被移到标志寄存器的CF位&#xff0c;左边空出来的位置用0填充 ;目的操作数可以是8位或16位的通用寄存器或者内存单元 ;源操作数可以是数字1、8位立即数或者寄存器CL shr r/m8, …

7、Django Admin删除默认应用程序

admin文件 from django.contrib.auth.models import User, Groupadmin.site.unregister(User) admin.site.unregister(Group) 显示效果&#xff1a; 前 后

使用vscode debug cpp/python混合编程的程序(从python调用的C++编译的dll)

使用vscode debug cpp/python混合编程的程序&#xff08;从python调用的C编译的dll&#xff09; 1. 安装插件 Python C Debugger https://marketplace.visualstudio.com/items?itemNamebenjamin-simmonds.pythoncpp-debug 2. 在.vscode/launch.json中增加配置 拷贝自 https:…

K8S日志收集

本章主要讲解在 Kubernetes 集群中如何通过不同的技术栈收集容器的日志&#xff0c;包括程序直接输出到控制台日志、自定义文件日志等。 一、有哪些日志需要收集 为了更加方便的处理异常&#xff0c;日志的收集与分析极为重要&#xff0c;在学习日志收集之前&#xff0c;需要知…

矮草坪渲染尝试

本来说写unity里的&#xff0c;由于three测试方便&#xff0c;先试试three 这个图片是目标效果 可以看见草很矮&#xff0c;很密集&#xff0c;如果用instance来绘制的话&#xff0c;遭不住的 忽然发现这个效果很像绒毛效果 于是找了博客康康 https://zhuanlan.zhihu.com/p/256…

第二证券:涨停潮!传手机将使用钛金属外壳?

今天早盘&#xff0c;银行股再度重挫&#xff0c;导致上证指数、上证50纷乱创出阶段性新低&#xff0c;上证指数跌破2800点&#xff0c;小盘成长股则大面积反弹&#xff0c;创业板指、科创50等股指飘红。 盘面上&#xff0c;新式烟草、钛金属、锂矿、玻璃基板等板块涨幅居前&a…

glsl着色器学习(七)

先了解一个矩阵库twgl/m4 是一个4x4 矩阵数学转换函数的库 normalize(a, dst) 将一个向量除以它的欧几里得长度&#xff0c;归一化后返回参数"a"是一个vec3&#xff08;三维向量&#xff09;参数"dst"是用来接收结果的&#xff0c;如果不传&#xff0c;则…

【嵌入式体系结构复习资料】

选择&#xff1a; 1. 以下哪个不是嵌入式系统设计的主要目标&#xff1f;( D ) A&#xff0e;低成本 B.低功耗 C.实时要求高 D.超高性能 2&#xff0e; 嵌入式系统有别于其他系统的最大特点是&#xff08;A &#xff09;。 A&#xff0e;嵌入专用 B.高可靠 C.…

集成电路学习:什么是LCD液晶显示器

一、LCD&#xff1a;液晶显示器 LCD&#xff0c;全称Liquid Crystal Display&#xff0c;即液晶显示器&#xff0c;是一种平面超薄的显示设备。它由一定数量的彩色或黑白像素组成&#xff0c;放置于光源或者反射面前方。LCD的主要原理是以电流刺激液晶分子产生点、线、面配合背…

mysql 使用 general 开启SQL跟踪功能

查看当前状态 mysql> SHOW VARIABLES LIKE %general%; 启用 临时启用 SET GLOBAL general_logon; SET GLOBAL general_log_file/tmp/general.log; 永久启用 通过修改配置文件来启用,需要重启mysql服务 [mysqld] general_logON general_log_file/tmp/general.log 再次查看状态…

【保姆级教程】如何在Win11上搭建一个GPU环境

CUDA和CUDNN安装 CUDA安装 下载对应cuda环境 下载链接&#xff1a;https://developer.nvidia.com/cuda-downloads&#xff0c;图片下载的是 cuda_12.6.1_560.94_windows.exe 然后一路安装即可&#xff1a; 安装路径如下&#xff1a; CUDNN安装 打开cuDNN下载页面 解压后…

排查SQL Server中的内存不足及其他疑难问题

文章目录 引言I DMV 资源信号灯资源信号灯 DMV sys.dm_exec_query_resource_semaphores( 确定查询执行内存的等待)查询性能计数器什么是内存授予?II DBCC MEMORYSTATUS 查询内存对象III DBCC 命令释放多个 SQL Server 内存缓存 - 临时度量值IV 等待资源池 %ls (%ld)中的内存…

【408DS算法题】034进阶-22年真题_判断顺序存储二叉树是否是BST

Index 真题题目分析实现总结 真题题目 已知非空二叉树T的结点值均为正整数&#xff0c;采用顺序存储方式保存&#xff0c;数据结构定义如下: typedef struct { // MAX_STZE为已定义常量int SqBiTNode[MAX_SIZE]; // 保存二叉树结点值的数组int ElemNum; …

BM3D--Image Denoising by Sparse 3-D Transform-Domain Collaborative Filtering

系列文章目录 文章目录 系列文章目录前言稀疏三维变换域协同滤波图像去噪摘要1 引言2 分组和协作过滤A.分组B.按匹配分组C.协同过滤D.基于变换域收缩的协同过滤 3 算法结论 前言 论文地址 如果下载不了可以从 https://download.csdn.net/download/m0_70420861/89708940 获取 …

Pytorch安装 CUDA Driver、CUDA Runtime、CUDA Toolkit、nvcc、cuDNN解释与辨析

Pytorch的CPU版本与GPU版本 Pytorch的CPU版本 仅在 CPU 上运行&#xff0c;适用于没有显卡或仅使用 CPU 的机器。安装方式相对简单&#xff0c;无需额外配置 CUDA 或 GPU 驱动程序。使用方式与 GPU 版相同&#xff0c;唯一不同的是计算将自动在 CPU 上进行。 Pytorch的GPU版…