Java_23_并发包

news2024/10/10 14:31:28

并发包

  1. 并发包的来历:
    在实际开发中如果不需要考虑线程安全问题,大家不需要做线程安全,因为如果做了反而性能不好!
    但是开发中有很多业务是需要考虑线程安全问题的,此时就必须考虑了。否则业务出现问题。
    Java为很多业务场景提供了性能优异,且线程安全的并发包,程序员可以选择使用!

  2. Map集合中的经典集合:HashMap它是线程不安全的,性能好

    1. 如果在要求线程安全的业务情况下就不能用这个集合做Map集合,否则业务会崩溃~
    2. 为了保证线程安全,可以使用Hashtable。注意:线程中加入了计时
    3. Hashtable是线程安全的Map集合,但是性能较差!(已经被淘汰了,虽然安全,但是性能差)
    4. 为了保证线程安全,再看ConcurrentHashMap(不止线程安全,而且效率高,性能好,最新最好用的线程安全的Map集合)
    5. ConcurrentHashMap保证了线程安全,综合性能较好!
  3. 小结:
    HashMap是线程不安全的。
    Hashtable线程安全基于synchronized,综合性能差,被淘汰了。
    ConcurrentHashMap:线程安全的,分段式锁,综合性能最好,线程安全开发中推荐使用

HashMap线程不安全验证及解决方案

public class ConcurrentHashMapDemo01 {
    //演示HashMap在高并发下的线程不安全性
    public static Map<String ,String> maps = new HashMap<>();

    public static void main(String[] args){
        Runnable target = new MyRunnable();
        Thread t1 = new Thread(target,"Thread-01");
        Thread t2 = new Thread(target,"Thread-02");

        t1.start();
        t2.start();

        try {
            t1.join();  //让两个线程跑完 使主线程不抢t1的CPU
            t2.join();  //只能t1,t2两个互相抢
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //等线程执行完毕获取集合最终元素个数
        System.out.println("元素个数:" + maps.size());
    }
}
class MyRunnable implements Runnable{
    @Override
    public void run(){
        for(int i = 1;i <= 500000;i ++){  //第一个线程加了50万,第二个线程也加了50万
            ConcurrentHashMapDemo01.maps.put(Thread.currentThread().getName() + i,Thread.currentThread().getName() + i);
        }
    }
}

输出结果:元素个数:947823 不是1000000

public static Map<String ,String> maps = new Hashtable<>();

定义成这种线程就安全了,但性能差,源码全是加锁
在这里插入图片描述

public static Map<String ,String> maps = new ConcurrentHashMap<>();//线程安全,性能得到极大提升

在这里插入图片描述

CountDownLatch并发包

  1. CountDownLatch允许一个或多个线程等待其他线程完成操作,再执行自己。

    1. 例如:线程1要执行打印:A和C,线程2要执行打印:B,但线程1在打印A后,要线程2打印B之后才能打印C,所以:线程1在打印A后,必须等待线程2打印完B之后才能继续执行
  2. 需求:
    提供A线程,打印 A , C
    提供B线程,打印 B

  3. 构造器:
    public CountDownLatch(int count)// 初始化唤醒需要的down几步。

  4. 方法:
    public void await() throws InterruptedException// 让当前线程等待,必须down完初始化的数字才可以被唤醒,否则进入无限等待
    public void countDown() // 计数器进行减1 (down 1)

  5. 小结:
    CountDownLatch可以用于让某个线程等待几步才可以继续执行, 从而可以实现控制线程执行的流程
    创建了几个Down就要c.countDown();几次,否则会出错!!!

public class CountDownLatchDemo01 {
    public static void main(String[] args) {
        //创建countdownlatch对象用于监督A、B线程执行情况_监督
        CountDownLatch c = new CountDownLatch(1);
        new MyThread_A(c).start();
        new MyThread_B(c).start();
    }
}
class MyThread_A extends Thread{
    private CountDownLatch c;

    public MyThread_A(CountDownLatch c) {
        this.c = c;
    }

    @Override
    public void run(){
        System.out.println("A");
        //等待自己,当前线程让出CPU等待自己
        try {
            c.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("C");
    }
}
class MyThread_B extends Thread{
    private CountDownLatch c;

    public MyThread_B(CountDownLatch c) {
        this.c = c;
    }

    @Override
    public void run(){
        System.out.println("B");
        c.countDown(); //让计数器减1,被等待的线程就唤醒了
    }
}

CyclicBarrier并发包

  1. CyclicBarrier作用:
    某个线程任务必须等待其他线程执行完毕以后才能最终触发自己执行。
  2. 例如:公司召集5名员工开会,等5名员工都到了,会议开始。
    我们创建5个员工线程,1个开会任务,几乎同时启动
    使用CyclicBarrier保证5名员工线程全部执行后,再执行开会线程。
  3. 构造器:
    public CyclicBarrier(int parties, Runnable barrierAction)
    // 用于在线程到达屏障5时,优先执行barrierAction,方便处理更复杂的业务场景
  4. 方法:
    public int await()
    // 每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞
  5. 小结:
    可以实现多线程中,某个任务在等待其他线程执行完毕以后触发。
    循环屏障可以实现达到一组屏障就触发一个任务执行!
public class CyclicBarrierDemo01 {
    public static void main(String[] args) {
        //2.创建循环屏障对象,等到5个线程执行完毕后触发一次线程任务(开会)
        CyclicBarrier c = new CyclicBarrier(5,new Meeting() );
        //1.创建一个任务循环屏障对象
        for(int i = 1;i <= 10;i ++){
            try {
                Thread.sleep(1000);

            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            new EmployeeThread("Employee-" + i,c).start();
        }
    }
}
class Meeting implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "开始组织会议!");
    }
}
class  EmployeeThread extends Thread{
    private CyclicBarrier c;
    public EmployeeThread(String name,CyclicBarrier c){
        super(name);
        this.c = c;
    }
    @Override
    public void run() {
            System.out.println(Thread.currentThread().getName() + "正在进入会议室……");
        try {
            c.await();//每个线程调用await方法,告诉c我已经到达了屏障,然后当前线程被回收
        } catch (InterruptedException | BrokenBarrierException e) {
            throw new RuntimeException(e);
        }
    }
}

达到一组屏障就触发一个任务执行!达到两组屏障就触发两个任务执行!

Semaphore并发包(*)

  1. 引入:

    1. Semaphore(发信号)的主要作用是控制线程的并发数量
    2. synchronized可以起到"锁"的作用,但某个时间段内,只能有一个线程允许执行。
      Semaphore可以设置同时允许几个线程执行。
    3. Semaphore字面意思是信号量的意思,它的作用是控制访问特定资源的线程数目。
  2. Semaphore的构造器:

    1. public Semaphore(int permits): permits 表示许可线程的数量
    2. public Semaphore(int permits, boolean fair):fair 表示公平性,如果这个设为 true 的话,下次执行的线程会是等待最久的线程
    3. Semaphore的方法:
      public void acquire() throws InterruptedException 表示获取许可
      public void release() release() 表示释放许可
  3. 小结:
    Semaphore可以控制并发线程同时进行的数量。

public class SemaphoreDemo01 {
    public static void main(String[] args) {
        Service service = new Service(); //一个业务,多个线程调用
        for(int i = 1;i <= 5;i ++) //5个线程
        {
            Thread a = new MyThread(service);
            a.start();
        }
    }
}
//线程类跑代码
class MyThread extends Thread{
    private Service service;
    public MyThread(Service service){
        this.service = service;
    }
    @Override
    public void run() {
        service.login();
    }
}
//业务
class Service{
    //表示许可!最多允许1个线程执行acquire()和release()之间的内容
    private Semaphore semaphore = new Semaphore(1); //同时只允许1个进来 控制流量
    //登录功能
    public void login(){
        try {
            semaphore.acquire(); //上锁
            System.out.println(Thread.currentThread().getName()
                    + "进入时间:" + System.currentTimeMillis());
            try {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + "登录成功!");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName()
                    + "离开时间:" + System.currentTimeMillis());
            semaphore.release(); //开锁
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

Exchanger并发包

  1. 作用

    1. Exchanger(交换者)是一个用于线程间协作的工具类
    2. Exchanger用于进行线程间的数据交换
    3. 这两个线程通过exchange方法交换数据,如果第一个线程先执行exchange()方法,它会一直等待第二个线程也执行exchange方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。
  2. Exchanger构造方法:
    public Exchanger()
    Exchanger重要方法:
    public V exchange(V x)

  3. 分析:
    (1)需要2个线程
    (2)需要一个交换对象负责交换两个线程执行的结果。

  4. 小结:
    Exchanger可以实现线程间的数据交换。
    一个线程如果等不到对方的数据交换就会一直等待。
    我们也可以控制一个线程等待的时间。
    必须双方都进行交换才可以正常进行数据的交换。

public class ExchangerDemo01 {
    public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<>();
        new Boy(exchanger).start();
        new Girl(exchanger).start();
    }
}
class Boy extends Thread{
    private Exchanger<String> exchanger;
    public Boy(Exchanger<String> exchanger){
        this.exchanger = exchanger;
    }
    @Override
    public void run() {
        //交换结果
        try {
            System.out.println("男孩开始制作定情信物:心锁");
            String rs = exchanger.exchange("心锁");
            System.out.println("男孩收到了:" + rs);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

class Girl extends Thread{
    private Exchanger<String> exchanger;
    public Girl(Exchanger<String> exchanger){
        this.exchanger = exchanger;
    }
    @Override
    public void run() {
        System.out.println("女孩开始制作定情信物:心匙");
        //交换结果
        try {
            String rs = exchanger.exchange("心匙");
            System.out.println("女孩收到了" + rs);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

时间延时判断

public class ExchangerDemo01 {
    public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<>();
        new Boy(exchanger).start();
        new Girl(exchanger).start();
    }
}
class Boy extends Thread{
    private Exchanger<String> exchanger;
    public Boy(Exchanger<String> exchanger){
        this.exchanger = exchanger;
    }
    @Override
    public void run() {
        //交换结果
        try {
            System.out.println("男孩开始制作定情信物:心锁");
            //等待5秒,对方还不交换就抛出异常
            String rs = exchanger.exchange("心锁",5, TimeUnit.SECONDS);
            System.out.println("男孩收到了:" + rs);
        } catch (InterruptedException | TimeoutException e) {
            throw new RuntimeException(e);
        }
    }
}

class Girl extends Thread{
    private Exchanger<String> exchanger;
    public Girl(Exchanger<String> exchanger){
        this.exchanger = exchanger;
    }
    @Override
    public void run() {
        System.out.println("女孩开始制作定情信物:心匙");
        //交换结果
        try {
            Thread.sleep(6000); //犹豫6秒
            String rs = exchanger.exchange("心匙");
            System.out.println("女孩收到了" + rs);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

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

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

相关文章

考公笔记题

一、考公报名网址 国家公务员局&#xff1a;国家公务员局 二、历年题库 华图在线&#xff1a;国省考公务员题库_公职教育类在线题库-华图在线 公务员&#xff1a;《行测》与《申论》 重点学习&#xff1a; 判断推理&#xff08;图形推理、定义判断&#xff08;影响不大&am…

vue中的数据代理

vue数据代理 Vue实现数据代理的核心----Object.defineProperty(); 数据代理 数据代理的定义是&#xff1a;一个对象操作(读\写)另一个对象中的属性和方法。 // 数据代理&#xff1a;通过一个对象代理对另一个对象中属性的操作&#xff08;读/写&#xff09;let obj { x: 100…

STM32之智能小车,手把手从0到1,模块化编程

小车介绍 本博文将会从0到1实现一个智能小车&#xff0c;该小车实现功能&#xff1a;1. 摇头避障模式、2. 跟随模式、3. 循迹模式、4. 小车测速并显示在OLED屏幕、5. 语音控制小车等等。 硬件组成 STM32F103开发板、小车套件、L9110S电机模块、超声波模块&#xff08;HC-SR04&a…

代码随想录算法训练营第二十五天 | 读PDF复习环节3

读PDF复习环节3 本博客的内容只是做一个大概的记录&#xff0c;整个PDF看下来&#xff0c;内容上是不如代码随想录网站上的文章全面的&#xff0c;并且PDF中有些地方的描述&#xff0c;是很让我疑惑的&#xff0c;在困扰我很久后&#xff0c;无意间发现&#xff0c;其网站上的讲…

Ubuntu-解决包依赖关系

Ubuntu-解决包依赖关系的办法 安装软件包的时候&#xff0c;有时会遇到类似下图的依赖问题&#xff0c;无法正常安装&#xff0c;下面提供三种方法解决依赖问题。 1.可以尝试用下面方法处理依赖问题&#xff0c;紧跟前一条安装命令后面输入下面命令&#xff0c;然后再执行安装…

第一次使用easyExcel报错信息记录 NullPointerException + MultipartException

第一次使用easyExcel报错信息记录 文章目录 第一次使用easyExcel报错信息记录NullPointerExceptionMultipartException NullPointerException 使用easyExcel报的错误 显示我的easyExcel监听器中出现了空指针异常 //报错信息 Creating a new SqlSessionClosing non transacti…

【Ajax】笔记-同源策略

同源策略(Same-Origin Policy)&#xff0c;是浏览器的一种安全策略 同源&#xff08;即url相同&#xff09;&#xff1a;协议、域名、端口号 必须完全相同。&#xff08;请求是来自同一个服务&#xff09; 跨域&#xff1a;违背了同源策略&#xff0c;即跨域。 ajax请求是遵循…

手把手教-gd32f450基于rt-thread发布的bsp包手动添加以太网外设

一、开发环境 rt-thread发布版本4.1.0&#xff1b; bsp包选用的是gd32目录下的gd32450z-eval rt-thread-v4.1.0\bsp\gd32\gd32450z-eval\ 开发板gd32f450z系列开发板。 二、手动添加以太网ETH外设 先看下初始结构 可以看到&#xff0c;配置中什么也没有。 手动添加步骤如下&…

27.提示卡片

提示卡片 html部分 <div class"msg-list"></div><button class"btn">点我看提示</button>css部分 *{margin: 0;padding: 0; }body{background-color: rebeccapurple;height: 100vh;overflow: hidden;display: flex;justify-con…

机器学习入门之 特征工程

数据集 数据集划分 ,训练集与 测试集合 from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.feature_extraction import DictVectorizer from sklearn.feature_extraction.text import CountVectorizer, TfidfVecto…

【FPGA/D6】

2023年7月25日 VGA控制器 视频23notecodetb 条件编译error时序图保存与读取&#xff1f;&#xff1f;RGBTFT显示屏 视频24PPI未分配的引脚或电平的解决方法 VGA控制器 视频23 note MCU单片机 VGA显示实时采集图像 行消隐/行同步/场同步/场消隐 CRT&#xff1a;阴极射线管 640…

8.9 PowerBI系列之DAX函数专题- TopN和BottomN和otherN的实现

需求 实现 1 summary table summarize(order_2,order_2[产品子类别],"订单金额",sum(order[订单金额])) 2 bottom5 table topn(5,summary table,summary table[订单金额],desc) // var v_sum_table summarize(order_2,order_2[产品子类别],"订单金额",…

【Linux】常见的基本指令详解

Linux常见的基本指令 一、什么是 Linux二、Linux 中常见的指令1. ls 指令2. pwd 命令3. cd 指令4. touch 指令5. mkdir 指令6. rmdir 指令 && rm 指令7. man 指令8. cp 指令9. mv 指令10. cat 指令11. more 指令12. less 指令13. wc 指令和 uniq 指令14. head 指令15. …

AIGC书籍推荐:《生成式深度学习的数学原理》

生成式 AI 使用各种机器学习算法&#xff0c;从数据中学习要素&#xff0c;使机器能够创建全新的数字视频、图像、文本、音频或代码等内容。生成式 AI 技术在近两年取得了重大突破&#xff0c;产生了全球性的影响。它的发展离不开近年来生成式深度学习大模型的突破。与一般意义…

【学习心得】sublime text 4 自定义编译系统

一、问题描述 在电脑中有多个版本的Python解释器&#xff0c;而sublime默认选择最新版本的解释器&#xff0c;如何指定自己想要的解释器呢&#xff1f; 二、自定义编译系统 1、选择新建编译系统&#xff08;如图&#xff09; 2、重写两个键值对&#xff08;只修改中文部分其…

线性代数(主题篇):第三章:向量组 、第四章:方程组

文章目录 第3章 n维向量1.概念(1)n维单位列向量 2.向量、向量组的的线性关系(线性相关性)(1)线性表示 &#xff1a;AXβ(2)线性相关、线性无关&#xff1a; AX0①线性相关②线性无关③线性相关性7大定理 3.极大线性无关组、等价向量组、向量组的秩1.极大线性无关组2.等价向量组…

人工智能术语翻译(三)

文章目录 摘要IJKL 摘要 人工智能术语翻译第二部分&#xff0c;包括I、J、K、L开头的词汇&#xff01; I 英文术语中文翻译常用缩写备注I.I.D. Assumption独立同分布假设Identically Distributed同分布的Identifiable可辨认的Identity Function恒等函数Identity Mapping恒等…

基于Citespace、vosviewer、R语言的文献计量学可视化分析及SCI论文高效写作方法教程

详情点击链接&#xff1a;基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法 前言 文献计量学是指用数学和统计学的方法&#xff0c;定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体&#xff0c;注重量…

小程序插件接入指引

微信对话开放平台小程序插件 微信对话开放平台是以对话交互为核心, 为有客服需求的个人、企业和组织提供智能服务与用户管理的配置平台。开发者可利用我们提供的工具自主完成对话机器人的搭建。 微信对话开放平台小程序插件&#xff0c;提供两种调用方式&#xff0c;一种是有U…

jdk1.7官网免登录下载

官网地址&#xff1a; Java Archive Downloads - Java SE 7 (oracle.com) 点进去之后&#xff0c;就可以看见如下的的界面 打开迅雷&#xff0c;在下载中点击新建 补充&#xff1a; jdk各个版本的地址&#xff1a; Java Archive | Oracle