java中的集合(Collections)“线程安全”是什么?有哪些线程安全的集合工具

文章目录

  • 前言
  • 一、什么是线程安全?
  • 二、线程不安全的示例
  • 三、解决集合线程不安全的方案
    • 1、synchronized关键字
    • 2、lock机制
    • 3、java.util.Collections工具
    • 4、commons-collections工具
    • 5、guava工具
  • 总结


前言

在Java开发中,集合是最常用的API之一,JDK提供的集合也是非常强大,在实际的开发中能很方便的解决很多需求问题。但是经常会听到“集合线程安全”,那么什么是集合线程安全?不安全又是什么情况?


一、什么是线程安全?

凡事谈到线程安全,必然是多线程环境,如果是单线程应用,一般不会有线程安全的说法。另外就是线程安全的主角应该是共享数据。

如果用一句简单的话来总结,线程安全就是:在多线程的情况下,有一个共享数据能够按照我们自己设定的规则去变化。如果这个共享数据的变化没有按照我们既定的规则去执行,那线程就不安全了。

二、线程不安全的示例

今天我们主要讨论集合的线程安全,所以我们先给出一个集合的示例:

package com.test.collects;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;public class ThreadSafeTest {public static void main(String[] args) {Set<Integer> set = new HashSet<>();ExecutorService executorService = Executors.newFixedThreadPool(32);for (int i = 0; i < 1000; i++) {final int number = i;executorService.submit(() -> {set.add(number);});}executorService.shutdown();try {executorService.awaitTermination(5, TimeUnit.SECONDS);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Set size: " + set.size()); // 通常集合大小会等于1000,说明集合是线程安全的}
}

我们直接运行上面这段中

  • 我们模拟一个多线程环境,都向集合中添加数据,总共需要添加1000个
  • 正常情况下,最后集合的总数应该是1000,如果不是1000那么我们整个代码就存在问题,也就是线程竞争问题。由于竞争就造成了线程不安全。

直接运行会发现:

Set size: 969

多次运行,数值会不一样,有可能某一次刚好1000,这没有达到我们的预期。

三、解决集合线程不安全的方案

Java中处理线程安全的方式有很多,这里我给大家列出一些常用的方式。

1、synchronized关键字

我们改造一下上面的代码:

for (int i = 0; i < 1000; i++) {final int number = i;executorService.submit(() -> {synchronized (String.class){set.add(number);}});
}

再次运行多次,发现最终结果始终是1000

2、lock机制

private static final Lock lock=new ReentrantReadWriteLock().writeLock();
for (int i = 0; i < 1000; i++) {final int number = i;executorService.submit(() -> {lock.lock();try{set.add(number);}finally {//记得释放lock.unlock();}});
}

效果如上

3、java.util.Collections工具

java.util.Collections工具提供了创建线程安全的集合。这里我们只需要替换集合的创建方式即可。

Set<Integer> set = Collections.synchronizedSet(new HashSet<>());for (int i = 0; i < 1000; i++) {final int number = i;executorService.submit(() -> {set.add(number);});
}

4、commons-collections工具

使用commons-collections工具包需要加入maven依赖:

<dependency><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId><version>3.2.2</version>
</dependency>

然后也只需要修改创建集合的方式即可:

Set<Integer> set = SynchronizedSet.decorate(new HashSet<>());for (int i = 0; i < 1000; i++) {final int number = i;executorService.submit(() -> {set.add(number);});
}

5、guava工具

guava提供了很多集合的封装以及扩展,方式和commons一样,加入maven依赖:

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.1-jre</version>
</dependency>

然后修改代码:

Set<Integer> set = Sets.newConcurrentHashSet();for (int i = 0; i < 1000; i++) {final int number = i;executorService.submit(() -> {set.add(number);});
}

总结

最后大家可能会关系上面几种处理线程安全的方式中执行的效率问题。经测试对比,没有发现哪一种方式会有显著的提升,所有的差距在执行时间上也就是几十毫秒,而且各自的表现也不一定,也许我的测试方式不对。

在不要求极致的效率问题时,我感觉大家可以根据实际情况来选择

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

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

相关文章

ubuntu/Linux连接redis教程

在 Ubuntu 上连接 Redis 数据库&#xff0c;你可以使用 redis-cli 命令来进行连接。以下是在 Ubuntu 终端中连接到 Redis 的步骤&#xff1a; 打开终端&#xff08;Terminal&#xff09;。输入以下命令连接到 Redis 数据库&#xff1a;redis-cli -h -p -a <hostname>:…

基础---nginx 启动不了,跟 Apache2 服务冲突

文章目录 查看 nginx 服务状态nginx 启动后 访问页面 127.0.0.1停止 nginx 服务&#xff0c;访问不了页面停止/启动 Apache2 服务&#xff0c;启动 Apache2 页面访问显示正确nginx 莫名启动不了卸载 Apache2 服务器 启动 nginx &#xff0c;但是总是不能实现反向代理&#xff0…

提升数据分析效率,选择IBM SPSS Statistics专业统计分析软件

在当今信息爆炸的时代&#xff0c;数据已经成为决策的重要依据。对于研究人员、学者、企业管理者等群体来说&#xff0c;如何高效地进行数据分析并得出准确结论至关重要。而IBM SPSS Statistics作为一款专业统计分析软件&#xff0c;为用户提供了强大的工具和功能&#xff0c;助…

阿里云免费证书改为3个月,应对方法很简单

情商高点的说法是 Google 积极推进90天免费证书&#xff0c;各服务商积极响应。 情商低点的话&#xff0c;就是钱的问题。 现在基本各大服务商都在2024年停止签发1年期的免费SSL证书产品&#xff0c;有效期都缩短至3个月。 目前腾讯云倒还是一年期。 如果是一年期的话&#x…

速盾cdn:cdn节点缓存内容不一致怎么办?

在使用CDN服务时&#xff0c;有时候可能会遇到CDN节点缓存内容不一致的情况。这种情况会导致用户访问网站时获取到的内容不一致&#xff0c;给用户带来困惑和不良体验。那么当遇到这种情况时&#xff0c;我们应该如何解决呢&#xff1f; 首先&#xff0c;我们需要了解CDN是如何…

java maven聚合项目-子项目重写父项目的依赖版本无法生效

前言 项目的springboot版本2.6.13 项目主pom 引入了springboot的依赖配置 <dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><…

泽众云真机-机型支持ADB调试功能即将上线

最近云真机平台在线客服&#xff0c;收到很多咨询关于ADB调试功能&#xff0c;什么时候能更新&#xff1f;据小编所知&#xff0c;正在升级之中&#xff0c;有一块专门为了解决ADB调试功能提前准备&#xff0c;升级网络硬件设备&#xff0c;目前平台的功能已开发完成&#xff0…

#QT(一种朴素的计算器实现方法)

1.IDE&#xff1a;QTCreator 2.实验&#xff1a;这是全靠自己想法写的计算器&#xff0c;没有参考任何教程。 &#xff08;1&#xff09;这个计算器只要有运算符敲入就会进行一次运算&#xff0c;所以他没有先后之后&#xff0c;无法满足运算优先级。 &#xff08;2&#xff…

[Redis]——Redis持久化的两种方式RDB、AOF

目录 RDB快照模式 概念&#xff1a; 触发时机&#xff1a; 异步做快照 AOF追加模式 概念&#xff1a; 触发时机&#xff1a; bgrewriteaof命令&#xff1a; 比较两种模式&#xff1a; RDB快照模式 概念&#xff1a; RDB模式就是保存当前Redis的状态到本地磁盘文件&am…

kubeadm部署Kubernetes(k8s) 1.23.0高可用集群

Kubernetes介绍 kubernetes(k8s)是2015年由Google公司基于Go语言编写的一款开源的容器集群编排系统,用于自动化容器的部署、扩缩容和管理; kubernetes(k8s)是基于Google内部的Borg系统的特征开发的一个版本,集成了Borg系统大部分优势; 官方地址:https://Kubernetes…

AttributeError: cannot assign module before Module.__init__() call

原因 调用了自定义的类&#xff0c;但是在自定义的类的__init__函数下面没有写super( XXX, self ).init() 错误案例 import torch import torch.nn as nnclass SelfAttention(nn.Module):""" Self-Attention """def __init__(self, n_head, d…

HTML5打开本地app应用的方法

大家好我是咕噜美乐蒂&#xff0c;很高兴又和大家见面了&#xff01; 打开本地应用程序是一种常见的需求&#xff0c;特别是在Web应用程序需要与本地设备或应用程序进行交互时。HTML5并不直接支持通过Web页面直接打开本地应用程序&#xff0c;但可以通过一些间接的方式实现这一…

【vue.js】文档解读【day 4】 | 事件处理

如果阅读有疑问的话&#xff0c;欢迎评论或私信&#xff01;&#xff01; 文章目录 事件处理前言监听事件内联事件处理器方法事件处理器方法与内联事件判断在内联处理器中调用方法在内联事件处理器中访问事件参数修饰符事件修饰符按键修饰符常规按键别名系统按键别名组合按键ex…

3d场景重建图像渲染 | 神经辐射场NeRF(Neural Radiance Fields)

神经辐射场NeRF&#xff08;Neural Radiance Fields&#xff09; 概念 NeRF&#xff08;Neural Radiance Fields&#xff0c;神经辐射场&#xff09;是一种用于3D场景重建和图像渲染的深度学习方法。它由Ben Mildenhall等人在2020年的论文《NeRF: Representing Scenes as Neur…

TVM_深度学习编译器

TVM_深度学习编译器 TVM所做的是要比传统compiler更偏上层的&#xff0c;你可以把它理解成source-to-source compiler&#xff0c;需要其他的后端(backend)来生成最后的指令。比如当编译的Target是Intel CPU时&#xff0c;翻译的顺序是Relay IR -> TVM IR/ Halide IR ->…

一、C#冒泡排序算法

一、C#冒泡排序算法 简介 冒泡排序算法是一种基础的排序算法&#xff0c;它的实现原理比较简单。核心思想是通过相邻元素的比较和交换来将最大&#xff08;或最小&#xff09;的元素逐步"冒泡"到数列的末尾。 实现原理 冒泡排序是一种简单的排序算法&#xff0c;其…

CSS Module

CSS Module的作用&#xff1a;将CSS样式作用域限制在特定的组件范围内&#xff0c;以避免全局样式污染和命名冲突。 Vue中如何实现样式模块…

【TB作品】MSP430单片机,音乐播放器,四首音乐,八音盒,Proteus仿真

文章目录 题目要求仿真结果实验报告&#xff1a;基于MSP430单片机的八音盒设计实验目的实验设备实验原理总结 代码和仿真图 题目要求 八音盒 本设计利用MSP430单片机结合内部定时器及LED/LCD,设计一个八音盒,按下单键可以演奏预先设置的歌曲旋律。 基本要求: 使用LED/LCD显示器…

JAVA基础:数组、重载、数据类型、封装、字符串、静态、继承、重写、多态、代码块、权限、接口、内部类

1 数组 //静态初始化 int[] arr1new int[]{1,2,3,4} //简化形式 int[] arr2{1,2,3,4} //动态初始化 int[] arr3new int[5] 2 方法重载 在同一个类中的多个方法的方法名相同,参数个数不同&#xff0c;参数类型不同&#xff0c;参数类型顺序不同 public class Test1 {public …

【javaWeb】在webapp中手动发布一个应用

标题 &#x1f432;一、为什么要在webapp中手动发布一个应用&#x1f389;二、手动发布步骤1.下载Tomcat2.解压并安装3.在webapps中创建文档 ✨三、总结 &#x1f432;一、为什么要在webapp中手动发布一个应用 好处解释灵活性手动发布应用程序可以根据自己的需求进行自定义配置…