从零学Java 线程安全的集合

news2024/11/18 16:52:46

线程安全的集合

文章目录

  • 线程安全的集合
    • 1 List 和 Set体系
      • Collections中的工具方法
      • 1.1 CopyOnWriteArrayList
      • 1.2 CopyOnWriteArraySet
      • 1.3 ConcurrentHashMap
    • 2 CAS算法
    • 3 Queue接口(队列)
      • 3.1 ConcurrentLinkedQueue
      • 3.2 BlockingQueue接口(阻塞队列)

Collection体系集合、以及线程安全集合。

在这里插入图片描述

注:下划线代表线程安全集合

1 List 和 Set体系

Collections中的工具方法

Collections工具类中提供了多个可以获得线程安全集合的方法。

  • public static Collection synchronizedCollection(Collection c)
  • public static List synchronizedList(List list)
  • public static Set synchronizedSet(Set s)
  • public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
  • public static SortedSet synchronizedSortedSet(SortedSet s)
  • public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)

JDK1.2提供,接口统一、维护性高,但性能没有提升,均以synchonized实现。

1.1 CopyOnWriteArrayList

  • 线程安全的ArrayList,加强版读写分离。
  • 写有锁,读无锁,读写之间不阻塞,优于读写锁。
  • 写入时,先copy一个容器副本、再添加新元素,最后替换引用。
  • 使用方式与ArrayList无异。

1.2 CopyOnWriteArraySet

  • 线程安全的Set,底层使用CopyOnWriteArrayList实现。
  • 唯一不同在于,使用addIfAbsent()添加元素,会遍历数组
  • 如存在元素,则不添加(扔掉副本)。

1.3 ConcurrentHashMap

JDK 1.7

  • 初始容量默认为16段(Segment),使用分段锁设计。
  • 不对整个Map加锁,而是为每个Segment加锁。
  • 当多个对象存入同一个Segment时,才需要互斥。
  • 最理想状态为16个对象分别存入16个Segment,并行数量16。
  • 使用方式与HashMap无异。

JDK 1.8

  • 改为CAS无锁算法。

eg:

public class TestThreadSafe {
    public static void main(String[] args) {
		//ArrayList<String> list=new ArrayList<>();
        //CopyOnWriteArrayList list=new CopyOnWriteArrayList();
        //CopyOnWriteArraySet set=new CopyOnWriteArraySet();
        ConcurrentHashMap<String,String> hashMap=new ConcurrentHashMap<>();
        ExecutorService es = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            es.submit(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 10; j++) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        hashMap.put(Thread.currentThread().getName()+"..."+j,"xxx");
                    }
                }
            });
        }
        es.shutdown();
        while(!es.isTerminated());
        System.out.println("元素个数:"+hashMap.size());
    }
}

2 CAS算法

CAS:Compare And Swap(比较交换算法)

  • 其实现方式是基于硬件平台的汇编指令,是靠硬件来实现的,效率高。
  • 并且比较和交换过程是同步的。
  • CAS是一种乐观锁。

乐观锁:

  • 总是认为是线程安全,不怕别的线程修改变量,如果修改了再重新尝试,直到成功。
  • CAS是乐观锁。

悲观锁:

  • 总是认为线程不安全,不管什么情况都进行加锁,要是获取锁失败,就阻塞。
  • synchronized、ReentrantLock是悲观锁。

CAS比较交换算法,修改的方法包含三个核心参数(V,E,N)

  • V:要更新的变量、E:预期值、N:新值。
  • 只有当V==E时,V=N;否则表示已被更新过,则取消当前操作,继续判断直到成功。

eg:

使用代码模拟CAS算法

public class TestCAS {
    public static void main(String[] args) {
        Cas cas=new Cas();
        ExecutorService es = Executors.newFixedThreadPool(100);
        for (int i = 0; i < 100; i++) {
            es.submit(() -> {
                while(true) {
                    int old = cas.getV();
                    boolean b = cas.compareAndSwap(old, new Random().nextInt(100));
                    System.out.println(Thread.currentThread().getName()+"..."+b);
                    if(b){
                        break;
                    }
                }
            });
        }
        es.shutdown();
    }
    static class Cas{
        private int V;//更新的变量
        //获取V的值
        public int getV(){
            return V;
        }
        public synchronized boolean compareAndSwap(int E,int N){
            if(E==V){
                V=N;
                return true;
            }
            return false;
        }
    }
}

3 Queue接口(队列)

Collection的子接口,表示队列FIFO(First In First Out)

常用方法:

  • 抛出异常:
    • boolean add(E e) //顺序添加一个元素(到达上限后,再添加则会抛出异常)
    • E remove() //获得第一个元素并移除(如果队列没有元素时,则抛异常)
    • E element() //获得第一个元素但不移除(如果队列没有元素时,则抛异常)
  • 返回特殊值:推荐使用
    • boolean offer(E e) //顺序添加一个元素 (到达上限后,再添加则会返回false)
    • E poll() //获得第一个元素并移除 (如果队列没有元素时,则返回null)
    • E peek() //获得第一个元素但不移除 (如果队列没有元素时,则返回null)

3.1 ConcurrentLinkedQueue

线程安全、可高效读写的队列,高并发下性能最好的队列。

  • 采用CAS比较交换算法

eg:

public class TestQueue {
    public static void main(String[] args) {
//        Queue<String> queue=new LinkedList<>();
        Queue<String> queue=new ConcurrentLinkedQueue<>();
        //入队
//        queue.offer("aaa");
//        queue.offer("bbb");
//        queue.offer("ccc");
        ExecutorService es = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 3; i++) {
            es.submit(new Runnable() {
                @Override
                public void run() {
                    queue.offer(Thread.currentThread().getName());
                }
            });
        }
        //出队
        es.shutdown();
        while(!es.isTerminated());
        int count=queue.size();
        for (int i = 0; i < count; i++) {
            System.out.println(queue.poll());
        }
    }
}

3.2 BlockingQueue接口(阻塞队列)

Queue的子接口,阻塞的队列,增加了两个线程状态为无限期等待的方法。

方法:

  • void put(E e) //将指定元素插入此队列中,如果没有可用空间,则等待。
  • E take() //获取并移除此队列头部元素,如果没有可用元素,则等待。
  • 可用于解决生产者、消费者问题。

实现类:

  • ArrayBlockingQueue:数组结构实现,有界队列。(手工固定上限)
  • LinkedBlockingQueue:链表结构实现,有界队列。(默认上限Integer.MAX_VALUE)

eg:

package StageOne.day21.demo02;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * @author 胡昊龙
 * @version 1.0
 * @description: TODO
 * @date 2024/1/16 14:32
 */
public class TestBlockingQueue {
    public static void main(String[] args) {
        //创建阻塞队列
        BlockingQueue<String> queue = new LinkedBlockingQueue<>(6);
        //创建线程池
        ExecutorService es = Executors.newCachedThreadPool();
        //提交任务
        es.submit(()->{
            for (int i = 0; i < 30; i++) {
                try {
                    queue.put("面包"+i);
                    System.out.println("生产了"+i);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        es.submit(()->{
            for (int i = 0; i < 30; i++) {
                try {
                    String take = queue.take();
                    System.out.println("消费了"+take);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        es.shutdown();
    }
}

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

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

相关文章

进程上下文的概念和切换简单通俗的解释

进程上下文是进程执行活动全过程的静态描述。我们把已执行过的进程指令和数据在相关寄存器与堆栈中的内容称为进程上文&#xff0c;把正在执行的指令和数据在寄存器与堆栈中的内容称为进程正文&#xff0c;把待执行的指令和数据在寄存器与堆栈中的内容称为进程下文。 实际上li…

基于杂交PSO算法的风光储微网日前优化调度(MATLAB实现)

微网中包含&#xff1a;风电、光伏、储能、微型燃气轮机&#xff0c;以最小化电网购电成本、光伏风机的维护成本、蓄电池充放电维护成本、燃气轮机运行成本及污染气体治理成本为目标&#xff0c;综合考虑&#xff1a;功率平衡约束、燃气轮机爬坡约束、电网交换功率约束、储能装…

细说JavaScript的数据类型(JavaScript的数据类型详解)

在JavaScript中有六种不同的数据类型&#xff0c;六种数据类型又分为5种简单数据类型&#xff08;基本数据类型&#xff09;和1中复杂数据类型&#xff08;引用数据类型&#xff09;&#xff0c;基本数据类型分为&#xff1a;字符串类型&#xff08;string&#xff09;、数值类…

机器学习周刊第六期:哈佛大学机器学习课、Chatbot Ul 2.0 、LangChain v0.1.0、Mixtral 8x7B

— date: 2024/01/08 — 吴恩达和Langchain合作开发了JavaScript 生成式 AI 短期课程&#xff1a;《使用 LangChain.js 构建 LLM 应用程序》 大家好&#xff0c;欢迎收看第六期机器学习周刊 本期介绍10个内容&#xff0c;涉及Python、机器学习、大模型等,目录如下&#xff…

SpringCloud Aliba-Nacos集群配置-从入门到学废【3】

&#x1f95a;今日鸡汤&#x1f95a; 修行之路&#xff0c;唯有不断超越自我&#xff0c;方能登上巅峰。 ——《武庚纪》 目录 &#x1f32d;1.Linu服务器上配置mysql &#x1f953;2.application.properties配置 &#x1f9c8;3.修改集群配置cluster.conf &#x1f9c2…

【复现】金和OA协同管理平台 任意文件上传漏洞_20

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 金和C6协同管理平台包括协同办公管理,人力资源管理,项目管理,客户关系管理,企业目标管理,费用管理,移动办公,微信办公等多个业务范…

python的装饰器详解

目录 一&#xff1a;介绍 二&#xff1a;在方法中使用 三&#xff1a;在类中使用 四&#xff1a;python自带的装饰器 一&#xff1a;介绍 Python的装饰器是一种高阶函数&#xff0c;它允许你在不改变函数内部逻辑的情况下&#xff0c;给函数添加额外的功能。装饰器本质上是…

Python 错误 Valueerror: Expected 2d Array Got 1d Array Instead

如您所知&#xff0c;每种编程语言都会遇到很多错误&#xff0c;有些是在运行时&#xff0c;有些是在编译时。 Python 在使用 numpy 库时有时会遇到数组错误。 当我们在 numpy 中传递一维数组而不是二维数组时&#xff0c;会发生错误 ValueError: Expected 2D array, got 1D a…

机器学习周刊第五期:一个离谱的数据可视化Python库、可交互式动画学概率统计、机器学习最全文档、快速部署机器学习应用的开源项目、Redis 之父的最新文章

date: 2024/01/08 这个网站用可视化的方式讲解概率和统计基础知识,很多内容还是可交互的,非常生动形象。 大家好,欢迎收看第五期机器学习周刊 本期介绍7个内容,涉及Python、概率统计、机器学习、大模型等,目录如下: 一个离谱的Python库看见概率,看见统计2024机器学习最…

前端面试题集合五(css)

CSS 面试知识点总结 本部分主要是笔者在复习 CSS 相关知识和一些相关面试题时所做的笔记&#xff0c;如果出现错误&#xff0c;希望大家指出&#xff01; 目录 1.介绍一下标准的 CSS 的盒子模型&#xff1f;低版本 IE 的盒子模型有什么不同的&#xff1f;2.CSS 选择符有哪些…

【代码随想录06】454. 四数相加 II 383. 赎金信 15. 三数之和 18. 四数之和

目录 454. 四数相加 II题目描述做题思路参考代码 383. 赎金信题目描述做题思路参考代码 15. 三数之和题目描述参考代码 18. 四数之和题目描述参考代码 454. 四数相加 II 题目描述 给你四个整数数组 nums1、nums2、nums3 和 nums4 &#xff0c;数组长度都是 n &#xff0c;请你…

LaTeX系列1——主结构

初学&#xff0c;可交流&#xff0c;轻喷 \documentclass{book} \begin{document} \title{Book Title} \author{Author Name} \date{\today} \maketitle\chapter{Introduction} This is the introduction chapter of the book.\section{First Section} The first section of t…

人工智能 | 生成式 AI 如何重塑开发流程和开发工具?

生成式 AI 如何重塑开发流程和开发工具&#xff1f; 生成式人工智能&#xff08;Generative Artificial Intelligence&#xff0c;GAI&#xff09;是一种基于大规模数据训练学习&#xff0c;从而生成新的原创内容的人工智能。生成式人工智能可以生成各种形式的数据&#xff0c…

Linux:网络文件共享服务和内网搭建yum仓库

目录 一、网络文件共享服务 1.储存类型 2.FTP文本传输协议 二、内网搭建yum仓库 1.通过ftp服务搭建内网yum仓库服务器 2.通过httpd协议搭建内网yum仓库服务器 一、网络文件共享服务 1.储存类型 分为三种&#xff1a; 直连式存储: Direct-Attached Storage&#xff0c;简…

大模型背景下计算机视觉年终思考小结(二)

1. 引言 尽管在过去的一年里大模型在计算机视觉领域取得了令人瞩目的快速发展&#xff0c;但是考虑到大模型的训练成本和对算力的依赖&#xff0c;更多切实的思考是如果在我们特定的小规模落地场景下的来辅助我们提升开发和落地效率。本文从相关数据集构造&#xff0c;预刷和生…

【干货】忘记设备IP咋整?查找设备IP地址这几种手段请收藏好~

前言&#xff1a; 拿到了设备但找不到设备IP地址的情况想必很多人都遇到过&#xff0c;又不想重置&#xff0c;怎么办嘞&#xff1f; 别急&#xff0c;可以通过机身标签上的唯一标识MAC地址查到IP&#xff0c;小云君给你支几招&#xff1a; 手段1 通过查询PC的ARP表项查询局…

Halcon提取彩色多通道图像的亚像素边缘edges_color_sub_pix算子

Halcon提取彩色多通道图像的亚像素边缘edges_color_sub_pix算子 如要要提取彩色多通道图像的亚像素边缘&#xff0c;可以使用edges_color sub pix算子。该算子与edges_sub_pix 算子的参数十分相似&#xff0c;但又有所区别。首先从名称上看&#xff0c;edges color sub pix 算…

Rust-析构函数

所谓“析构函数”(destructor),是与“构造函数”(constructor)相对应的概念。 “构造函数”是对象被创建的时候调用的函数&#xff0c;“析构函数”是对象被销毁的时候调用的函数。 Rust中没有统一的“构造函数”这个语法&#xff0c;对象的构造是直接对每个成员进行初始化完…

软件测试要学习的基础知识——白盒测试

白盒测试是通过检查软件内部的逻辑结构&#xff0c;对软件中的逻辑路径进行覆盖测试&#xff0c;以确定实际运行状态与预期状态是否一致。 白盒测试又被称为&#xff1a; 透明盒测试 结构化测试 逻辑驱动测试 基于代码的测试 白盒测试的常用技术分类 一、静态分析&#x…

GEE:机器学习分类中每个类别的概率图像可视化

作者:CSDN @ _养乐多_ 在 Google Earth Engine(GEE) 中应用机器学习分类器进行多分类时,有一个需求是想知道每个像素对于每个类别的分类概率。 比如在进行随机森林分类时,每个决策树会生成一个类别,通过投票选择票数最多的类别作为最终分类。除了最终分类结果,其他类别…