【不安全的集合类】同步容器(如ConcurrentHashMap)、并发集合(如CopyOnWriteArrayList)

本文主要是介绍【不安全的集合类】同步容器(如ConcurrentHashMap)、并发集合(如CopyOnWriteArrayList),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 一、List的线程不安全
    • 二、Set的线程不安全
    • 三、Map的线程不安全

日常我们用到的集合的情况会很多,在单线程的情况下,不用考虑到线程安全的问题,但是如果在多线程开发的过程中,我们该选择哪一种类型来保证线程安全性呢

一、List的线程不安全

我们先来看一个例子:

package com.atguigu.signcenter.nosafe;import java.util.ArrayList;
import java.util.UUID;/*** 题目:请举例说明集合类是不安全的* @author: jd* @create: 2024-09-02*/
public class NotSafeDemo {public static void main(String[] args) {ArrayList<String> StrList = new ArrayList<>();for (int i = 0; i <=30 ; i++) {new Thread(()->{StrList.add(UUID.randomUUID().toString().substring(0,8));System.out.println("StrList = " + StrList);},String.valueOf(i)).start();}}}

结果:从图中可以看出来,执行一段时间之后发生了错误;这个错误就是多线程任务中对同一个集合处理过程中出现了冲突的情况导致的
在这里插入图片描述
导致原因&解决方案
会出现ConcurrentModificationException是因为ArrayList的add方法不是线程安全的;当某个线程正在向List中写入数据时,另外一个线程同时进来写入,就会导致ConcurrentModificationException。

  1. 我们可以使用线程安全的集合类Vector,其add方法是同步方法(保证了数据一致性,但是访问性能下降);
  2. 使用Collections.synchronizedList(new ArrayList<>()) 创建一个线程安全的List (其实就是在add的时候使用了synchronized同步代码块);
  3. CopyOnWriteArrayList 写时复制ArrayList (多线程建议使用这个)
    Vector是线程安全的,能够保证数据一致性但是性能低;ArrayList牺牲了数据一致性提升了读写效率;现在想要保证数据一致性的同时也要保证读写效率,那应该怎么办?因此出现了读写分离的CopyOnWriteArrayList 。

CopyOnWriteArrayList的写时复制
我们可以先看看CopyOnWriteArrayList中add方法的源码

private transient volatile Object[] array;public boolean add(E e) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();   // 获取当前List中的所有元素int len = elements.length;  Object[] newElements = Arrays.copyOf(elements, len + 1);  // 拷贝旧元素到新的扩容的数组中newElements[len] = e;  // 添加新的值setArray(newElements);  // 更新return true;} finally {lock.unlock();}
}

CopyOnWrite容器即写时复制的容器,往一个容器中添加元素的时候,不直接往当前容器Object[]添加,而是现将当前容器Object[]进行Copy,而是复制出一个新的容器Object[] newElements向新容器添加元素,添加之后,再将原容器的引用指向新的容器setArray(newElements);这样做的好处时可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。同时添加元素的过程是通过ReentrantLock 锁来实现了同一时间内只有一个线程对此方法的访问。

二、Set的线程不安全

public class NotSafeDemo {public static void main(String[] args) {Set<String> set = new HashSet<>();for (int i = 1; i <= 30; i++) {new Thread(() -> {set.add(UUID.randomUUID().toString().substring(0, 8));System.out.println(set);}, String.valueOf(i)).start();}}
}

面这段代码同样会出现java.util.ConcurrentModificationException异常;同样可以使用Collections.synchronizedSet()和CopyOnWriteArraySet,其具体原理与List的一致。这里浅说一下HashSet的源码,HashSet其实就是一个HashMap,HashSet的中存的值是HashMap的key,HashMap中的Value是一个固定对象PRESENT。

三、Map的线程不安全

同样HashMap也是线程不安全的,可以使用集合工具类Collections.synchronizedMap(new HashMap<String, String>())和ConcurrentHashMap创建线程安全的HashMap

public class NotSafeDemo {public static void main(String[] args) {
//        HashMap<String, String> map = new HashMap<>();
//        HashMap<String, String> map1 = (HashMap<String, String>) Collections.synchronizedMap(new HashMap<String, String>());ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();for (int i = 1; i <= 30; i++) {new Thread(() -> {map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 8));System.out.println(map);}, String.valueOf(i)).start();}}
}

结果正确且正常结束
在这里插入图片描述

这篇关于【不安全的集合类】同步容器(如ConcurrentHashMap)、并发集合(如CopyOnWriteArrayList)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1132058

相关文章

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

客户案例:安全海外中继助力知名家电企业化解海外通邮困境

1、客户背景 广东格兰仕集团有限公司(以下简称“格兰仕”),成立于1978年,是中国家电行业的领军企业之一。作为全球最大的微波炉生产基地,格兰仕拥有多项国际领先的家电制造技术,连续多年位列中国家电出口前列。格兰仕不仅注重业务的全球拓展,更重视业务流程的高效与顺畅,以确保在国际舞台上的竞争力。 2、需求痛点 随着格兰仕全球化战略的深入实施,其海外业务快速增长,电子邮件成为了关键的沟通工具。

uva 11178 计算集合模板题

题意: 求三角形行三个角三等分点射线交出的内三角形坐标。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <

安全管理体系化的智慧油站开源了。

AI视频监控平台简介 AI视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界面上进行简单的操作,就可以实现全视频的接入及布控。摄像头管理模块用于多种终端设备、智能设备的接入及管理。平台支持包括摄像头等终端感知设备接入,为整个平台提

高并发环境中保持幂等性

在高并发环境中保持幂等性是一项重要的挑战。幂等性指的是无论操作执行多少次,其效果都是相同的。确保操作的幂等性可以避免重复执行带来的副作用。以下是一些保持幂等性的常用方法: 唯一标识符: 请求唯一标识:在每次请求中引入唯一标识符(如 UUID 或者生成的唯一 ID),在处理请求时,系统可以检查这个标识符是否已经处理过,如果是,则忽略重复请求。幂等键(Idempotency Key):客户端在每次

2024网安周今日开幕,亚信安全亮相30城

2024年国家网络安全宣传周今天在广州拉开帷幕。今年网安周继续以“网络安全为人民,网络安全靠人民”为主题。2024年国家网络安全宣传周涵盖了1场开幕式、1场高峰论坛、5个重要活动、15场分论坛/座谈会/闭门会、6个主题日活动和网络安全“六进”活动。亚信安全出席2024年国家网络安全宣传周开幕式和主论坛,并将通过线下宣讲、创意科普、成果展示等多种形式,让广大民众看得懂、记得住安全知识,同时还

K8S(Kubernetes)开源的容器编排平台安装步骤详解

K8S(Kubernetes)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8S容器编排平台的安装步骤、使用方式及特点的概述: 安装步骤: 安装Docker:K8S需要基于Docker来运行容器化应用程序。首先要在所有节点上安装Docker引擎。 安装Kubernetes Master:在集群中选择一台主机作为Master节点,安装K8S的控制平面组件,如AP

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext = new ClassPathXmlApplicationContext("bean.xml");} BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanF

容器编排平台Kubernetes简介

目录 什么是K8s 为什么需要K8s 什么是容器(Contianer) K8s能做什么? K8s的架构原理  控制平面(Control plane)         kube-apiserver         etcd         kube-scheduler         kube-controller-manager         cloud-controlle