线程不安全举例

news2024/11/18 23:46:02

1、举例说明集合类线程不安全

(1)查看源码可证明
看ArrayList源码
在这里插入图片描述

没有sync、lock,线程不安全

(2)创建多个线程写入读取数据

List<String> list =new ArrayList<>();
for (int i = 1; i <=30 ; i++) {
    new Thread(()->{
        list.add(UUID.randomUUID().toString().substring(0,8));
        System.out.println(list);
    },String.valueOf(i)).start();
}

(3)异常

java.util.ConcurrentModificationException
ArrayList在迭代的时候如果同时对其进行修改就会抛出java.util.ConcurrentModificationException异常并发修改异常。

(4)报并发修改异常
在这里插入图片描述

2、如何让集合变成线程安全

(1)Vector

List<String> list = new Vector<>();
 

在这里插入图片描述

看Vector的源码

public synchronized boolean add(E e) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}

有synchronized线程安全。
在这里插入图片描述

(2)Collections

List<String> list = Collections.synchronizedList(new ArrayList<>());

Collections提供了方法synchronizedList保证list是同步线程安全的。
那HashMap,HashSet是线程安全的吗?也不是
所以有同样的线程安全方法
在这里插入图片描述

(3)CopyOnWriteArrayList写时拷贝技术
在这里插入图片描述

List<String> list = new CopyOnWriteArrayList<>();

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

3、写时复制

(1)不加锁性能提升出错误,加锁数据一致性能下降

(2)CopyOnWriteArrayLis定义

A thread-safe variant of ArrayList in which all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying array.
CopyOnWriteArrayList是arraylist的一种线程安全变体,其中所有可变操作(add、set等)都是通过生成底层数组的新副本来实现的。

(3)举例
在这里插入图片描述

(4)CopyOnWrite理论

/**
 * Appends the specified element to the end of this list.
 *
 * @param e element to be appended to this list
 * @return {@code true} (as specified by {@link Collection#add})
 */
public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        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,然后向新的容器Object[] newElements里添加元素。
	添加元素后,再将原容器的引用指向新的容器setArray(newElements)。

这样做的好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。
所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

(5)扩展类比

1)HashSet

Set<String> set = new HashSet<>();//线程不安全
Set<String> set = new CopyOnWriteArraySet<>();//线程安全

HashSet底层数据结构是什么?
HashMap但HashSet的add是放一个值,而HashMap是放K、V键值对

public HashSet() {
    map = new HashMap<>();
} 
private static final Object PRESENT = new Object(); 
public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

2)HashMap

Map<String,String> map = new HashMap<>();//线程不安全
Map<String,String> map = new ConcurrentHashMap<>();//线程安全

(6)代码

package jucdemo;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
/**
 * 请举例说明集合类是不安全的
 */
public class NotSafeDemo {
    public static void main(String[] args) {
        Map<String,String> map = new ConcurrentHashMap<>();
        for (int i = 0; i <30 ; i++) {
            new Thread(()->{
              map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,8));
                System.out.println(map);
            },String.valueOf(i)).start();
        }
    }

    private static void setNoSafe() {
        Set<String> set = new CopyOnWriteArraySet<>();
        for (int i = 0; i <30 ; i++) {
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(set);
            },String.valueOf(i)).start();
        }
    }

    private static void listNoSafe() {
        //        List<String> list = Arrays.asList("a","b","c");
        //        list.forEach(System.out::println);
        //写时复制
        List<String> list = new CopyOnWriteArrayList<>();
        // new CopyOnWriteArrayList<>();
        //Collections.synchronizedList(new ArrayList<>());
        //new Vector<>();//new ArrayList<>();
        for (int i = 0; i <30 ; i++) {
                    new Thread(()->{
                        list.add(UUID.randomUUID().toString().substring(0,8));
                        System.out.println(list);
                    },String.valueOf(i)).start();
                }
    }
}

    /**
     * 写时复制
     CopyOnWrite容器即写时复制的容器。往一个容器添加元素的时候,不直接往当前容器Object[]添加,
     而是先将当前容器Object[]进行Copy,复制出一个新的容器Object[] newElements,然后向新的容器Object[] newElements里添加元素。
     添加元素后,再将原容器的引用指向新的容器setArray(newElements)。
     这样做的好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。
     所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
    
    public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }
     */

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

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

相关文章

2023年Web安全学习路线总结!430页Web安全学习笔记(附PDF)

关键词&#xff1a;网络安全入门、渗透测试学习、零基础学安全、网络安全学习路线、web安全攻防笔记、渗透测试路线图 网络安全的范畴很大&#xff0c;相较于二进制安全等方向的高门槛、高要求&#xff0c;Web安全体系比较成熟&#xff0c;在现阶段来看&#xff0c;但凡有自己…

k8s下安装redis

一、使用helm安装redis 执行以下命令添加redis的repo helm repo add bitnami https://charts.bitnami.com/bitnami 创建的master和replica pod的默认size是8Gi&#xff0c;如果k8s的node没有足够的空间&#xff0c;会抛出如下错误&#xff1a;default-scheduler 0/3 nodes …

安全防御 --- SSL VPN

附&#xff1a;无线项目介绍 SSL VPN 有浏览器的设备就可以使用SSL&#xff0c;进而使用SSL VPN。无需担心客户端问题&#xff0c;所以SSL VPN也称为无客户端VPN。SSL VPN在client to lan场景下特别有优势。 实际实现过程&#xff08;基于TCP实现&#xff09; &#xff08;1&…

Nginx SSL使用自制证书

1. 生成证书 keytool -genkey -v -alias <Alias别名> -keyalg RSA -keystore <KeyStore文件> -validity <有效期> keytool -genkey -v -alias nginx -keyalg RSA -keystore nginx.keystore -validity 36500 alias别名为 nginxkeystore文件为 nginx.keystore…

C/C++内存管理(内存分布、动态内存分配、动态内存分配与释放、内存泄漏等)

喵~ 内存之5大区&#xff08;栈区、堆区、静态区、常量区、代码区&#xff09;C/C中各自的内存分配操作符内存泄露?内存泄漏检测方法 内存之5大区&#xff08;栈区、堆区、静态区、常量区、代码区&#xff09; 1、栈区&#xff08;stack&#xff09;&#xff1a;由编译器自动分…

避雷投稿!这3本SCIE期刊处于On Hold状态!有剔除风险!

今年3月份科睿唯安剔除的大量期刊中&#xff0c;有几本期刊之前被WOS数据库标记为“On Hold”状态&#xff0c;后面也出现了一些期刊解除“On Hold”状态的情况。 目前&#xff0c;WOS数据库查询有3本SCIE期刊正处于“On Hold”状态&#xff0c;这是什么信号呢&#xff1f;对于…

org.apache.thrift.transport.TTransportException: GSS initiate failed

hive配置kerberos發現錯誤&#xff0c;就所有的配置都配好了&#xff0c;但是使用datagrip連接hive時報錯如下&#xff1a; org.apache.thrift.transport.TTransportException: GSS initiate failed 後面是沒有認證的原因&#xff0c;使用kinit 認證即可 還有一種情況是 我使…

7.1下周黄金非农数据是否会影响美联储七月暂停加息?

近期有哪些消息面影响黄金走势&#xff1f;下周黄金多空该如何研判&#xff1f; ​黄金消息面解析&#xff1a;周五(6月30日)&#xff0c;现货黄金价格收盘上涨&#xff0c;盘中一度升破1920美元关口。美国疲软的个人消费支出推动了美国国债收益率的下降&#xff0c;从而导致美…

libevent实践04:监听管道第二季

一 本次实例使用函数简介 事件集合初始化&#xff1a; struct event_base *event_init(void); 示例&#xff1a; struct event_base *base event_init(); 单个事件初始化 void event_set(struct event *ev, evutil_socket_t fd, short events,void (*callback)(evutil_s…

两小时快速入门 TypeScript 基础(二)面向对象

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;也会涉及到服务端&#xff08;Node.js 等&#xff09; &#x1f4c3;个人状态&#xff1a; 2023届本科毕业生&#xff0c;已拿多个前端 offer&#x…

【实战】 二、React 与 Hook 应用:实现项目列表 —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二)

文章目录 一、项目起航&#xff1a;项目初始化与配置二、React 与 Hook 应用&#xff1a;实现项目列表1.新建文件2.状态提升3.新建utils4.Custom Hook 学习内容来源&#xff1a;React React Hook TS 最佳实践-慕课网 相对原教程&#xff0c;我在学习开始时&#xff08;2023.0…

【每天40分钟,我们一起用50天刷完 (剑指Offer)】第十二天 12/50

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

服务运营|MS 论文解读:MIR 增强的Benders 分解用于具有到达率不确定性的多类服务系统人员调度问题

推文作者&#xff1a;王畅&#xff0c;蔡君洋&#xff0c;Guo 编者按 劳动力调度是服务系统运营的一个重要应用场景&#xff0c;当系统中的服务集和客户集异构且客户到达率不确定时&#xff0c;劳动力调度问题会变得特别复杂。本文因此引入了一个两阶段的随机整数规划模型&…

【静态单元格 Objective-C语言】

一、预习QQ动态 1.我们今天,是三、到四个任务,第一个任务,就是这个,预习QQ动态 OK,看到这个效果了吗 这是咱们第一个任务,第一个任务,是实现这么一个效果, 一看这个,就肯定是个啥,UITableView吧, 是不是肯定是一个TableView啊 又能滚动,又能显示一行一行的数据…

Qt QGraphicsScene、QGraphicsView类实现仪表盘

Qt QGraphicsScene、QGraphicsView类实现仪表盘 【1】UI界面设计【2】效果【3】QGraphicsScene简介【4】QGraphicsEllipseItem简介【5】QGraphicsPolygonItem简介【6】QGraphicsLineItem简介【7】QGraphicsView简介【8】仪表源码头文件源码 【1】UI界面设计 【2】效果 【3】QGr…

OpenStack(T版)——对象存储(Swift)服务介绍与安装

文章目录 OpenStack(T版)——对象存储(Swift)服务介绍与安装安装和配置(controller)准备安装和配置Swift对象存储服务组件创建账户 Ring创建容器 Ring创建对象 RingSwift 存储系统的主配置文件修改文件属主 安装和配置(compute)准备配置Swift对象存储服务组件 验证(1)加载环境变…

《程序员的AI书_从代码开始》第二章 手工实现神经网络

文章目录 2.1 感知器2.1.1 从神经元到感知器2.1.2 实现简单的感知器 2.1 感知器 2.1.1 从神经元到感知器 2.1.2 实现简单的感知器 class Perception(object):def __init__(self,eta0.01,iterations10):self.lr etaself.iterations iterationsself.w 0.0self.bias 0.0sel…

Red Hat宣布限制访问源代码,尚有两种方式可获取

日前Red Hat宣布限制访问Red Hat Enterprise Linux(RHEL)源代码&#xff0c;而此举也将影响AlmaLinux 、Rocky Linux 等下游发行版。 随即Rocky Linux发布了名为《Keeping Open Source Open》的博文。文中是这样说的&#xff1a;    Red Hat的**ERP**服务条款 (TOS) 和最终…

dotnet-dump/trace

一、dotnet-dump dotnet tool install -g dotnet-dump ps -ef | grep dotnet export PATH$PATH:$HOME/.dotnet/tools dotnet-dump collect --process-id 31555 #等待最后出输出&#xff1a;Writing full to /root/core_20230701_095230 #分析/root/core_20230701_095230文件 d…

【doxygen】支持 markdown 目录

文章目录 创建章节和子章节配置 doxygen Doxygen 不直接支持 Markdown 的 [toc] 语法。但是&#xff0c;你可以通过以下步骤手动创建目录&#xff1a; 创建章节和子章节 在 Markdown 文件中&#xff0c;使用标题标记&#xff08; # &#xff09;来创建章节和子章节。 Note:…