Java_23_并发包

并发包

  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的CPUt2.join();  //只能t1,t2两个互相抢} catch (InterruptedException e) {throw new RuntimeException(e);}//等线程执行完毕获取集合最终元素个数System.out.println("元素个数:" + maps.size());}
}
class MyRunnable implements Runnable{@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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{@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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.mzph.cn/news/9036.shtml

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

相关文章

RNN架构解析——传统RNN模型

目录 传统RNN的内部结构图使用RNN优点和缺点 传统RNN的内部结构图 使用RNN rnnnn.RNN(5,6,1) #第一个参数是输入张量x的维度&#xff0c;第二个是隐藏层维度&#xff0c;第三层是隐藏层的层数 input1torch.randn(1,3,5) #第一个是输入序列的长度&#xff0c;第二个是批次的样本…

Golang指针详解

要搞明白Go语言中的指针需要先知道3个概念&#xff1a;指针地址、指针类型和指针取值。 指针介绍 我们知道变量是用来存储数据的&#xff0c;变量的本质是给存储数据的内存地址起了一个好记的别名。比如我们定义了一个变量 a : 10 ,这个时候可以直接通过 a 这个变量来读取内存…

在centos 7系统docker上构建mysql 5.7

一、VM上已经安装centos 7.9&#xff0c;且已完成docker的构建 二、安装mysql5.7 安装镜像&#xff1a;[rootlocalhost lll]# docker pull mysql:5.7 查看镜像[rootlocalhost lll]# docker images 根据镜像id构建mysql容器&#xff0c;且分配端口号[rootlocalhost lll]# dock…

JVM(Java Virtual Machine)

哥几个来学 JVM 啦~~ 目录 &#x1f332;一、JVM 执行流程&#xff08; JVM 是如何运行的&#xff1f;&#xff09; &#x1f333;二、JVM 运行时数据区 &#x1f366;1. 堆&#xff08;线程共享&#xff09; &#x1f367;2. Java 虚拟机栈&#xff08;线程私有&#xff0…

关于我组件家庭服务器,挑选硬件设备的经历

目录 起因 升级——玩客云 原因 折腾日记 又升级——d2550工控主机 原因 折腾日记 又双升级——itx主机 原因 折腾日记 又双叒升级&#xff08;目前再用的机器&#xff09;——i9级x99平台e5v3主机 原因 折腾日记 心得 起因 起因大概在今年三月底四月初的时候&…

DuckDB全面挑战SQLite

概要 当我们想要在具有嵌入式数据库的本地环境中工作时&#xff0c;我们倾向于默认使用 SQLite。虽然大多数情况下这都很好&#xff0c;但这就像骑自行车去 100 公里之外&#xff1a;可能不是最好的选择。 这篇文章中将讨论以下要点&#xff1a; • DuckDB 简介&#xff1a;它…

uniapp WIFI上下班打卡

大纲 &#x1f959; uniapp官网&#xff1a;uni-app官网 &#x1f959; WIFI功能模块&#xff1a; 1、下载 wifi 插件 uni-WiFi 2、在 manifest.json 中 App权限配置中 配置权限 1. ACCESS_WIFI_STATE &#xff08;访问权限状态&#xff09; 2. CHANGE_WIFI_STATE&#xff…

SpringBoot整合ActiveMQ

ActiveMQ简单使用 JMS ActiveMQ 下载安装 https://activemq.apache.org/components/classic/download/解压缩文件。进入win64目录&#xff0c;双击运行activemq.bat文件&#xff0c;运行服务 将下面的网址输入到浏览器&#xff0c;用户名和密码都是admin SpringBoot整合Act…

外贸行业企业邮箱选择:安全好用的邮箱服务

随着全球化的发展&#xff0c;外贸行业在全球经济中越来越重要。作为一家从事对外贸易的企业&#xff0c;可靠、安全、易用的邮箱系统对于成功的国际交易至关重要。为您的企业选择正确的邮箱解决方案可能是一个挑战。为了使选择过程更加简化&#xff0c;我们在这里提供了一些提…

异构线程池的c++实现方案

概要 通常线程池是同质的&#xff0c;每个线程都可以执行任意的task&#xff08;每个线程中的task顺序执行&#xff09;&#xff0c;如下图所示&#xff1a; 但本文所介绍的线程和task之间有绑定关系&#xff0c;如A task只能跑在A thread上&#xff08;因此称为异构线程池&am…

2023云曦期中复现

目录 SIGNIN 新猫和老鼠 baby_sql SIGNIN 签到抓包 新猫和老鼠 看到反序列化 来分析一下 <?php //flag is in flag.php highlight_file(__FILE__); error_reporting(0);class mouse { public $v;public function __toString(){echo "Good. You caught the mouse:&…

Apache pulsar 技术系列-- 消息重推的几种方式

导语 Apache Pulsar 是一个多租户、高性能的服务间消息传输解决方案&#xff0c;支持多租户、低延时、读写分离、跨地域复制&#xff08;GEO replication&#xff09;、快速扩容、灵活容错等特性。在很多场景下&#xff0c;用户需要通过 MQ 实现消息的重新推送能力&#xff0c…

Python+Playwright自动化测试--标签页操作(tab)

1.简介 标签操作其实也是基于浏览器上下文&#xff08;BrowserContext&#xff09;进行操作的&#xff0c;而且宏哥在之前的BrowserContext也有提到过&#xff0c;但是有的童鞋或者小伙伴还是不清楚怎么操作&#xff0c;或者思路有点模糊&#xff0c;因此今天单独来对其进行讲…

nvidia-smi输出的结果代表什么

nvidia-smi(NVIDIA System Management Interface) 是基于nvml的gpu的系统管理接口,主要用于显卡的管理和状态监控。 nvidia-smi简称NVSMI&#xff0c;提供监控GPU使用情况和更改GPU状态的功能&#xff0c;是一个跨平台工具&#xff0c;支持所有标准的NVIDIA驱动程序支持的Linu…

【RS】基于规则的面向对象分类

ENVI使用最多的工具就是分类&#xff0c;这也是很多卫星影像的用途。在ENVI中有很多分类工具&#xff0c;如最基础的监督分类&#xff08;最大似然法、最小距离、支持向量机、随机森林&#xff09;、非监督分类&#xff08;K-means、IsoData&#xff09;&#xff0c;还有面向对…

13、PHP面向对象2(方法的访问控制、子类继承、常量)

1、类中的方法可以被定义为公有&#xff0c;私有或受保护。如果没有设置这些关键字&#xff0c;则该方法默认为公有。 public定义的方法&#xff0c;可以在类外使用。 protected定义的方法&#xff0c;只能在本类或子类的定义内使用。 private定义的方法&#xff0c;只能在本…

ubuntu开机自启动

ubuntu开机自启动 1、建一个test.sh脚本&#xff0c;并写入 #!/bin/sh gnome-terminal -x bash -c ‘cd /home/文件路径/;python3 main.py’ exit 0 2、:wq!保存 3、创建rc-local.service文件&#xff08;sudo vim /etc/systemd/system/rc-local.service&#xff09;&#xf…

Linux系统安装部署MySQL完整教程(图文详解)

前言&#xff1a;最近网上翻阅了大量关于Linux安装部署MySQL的教程&#xff0c;在自己部署的时候总是存在一些小问题&#xff0c;例如&#xff1a;版本冲突&#xff0c;配置失败和启动失败等等&#xff0c;功夫不负有心人&#xff0c;最后还是安装部署成功了&#xff0c;所以本…

[SQL系列] 从头开始学PostgreSQL 事务 锁 子查询

[SQL系列] 从头开始学PostgreSQL 索引 修改 视图_Edward.W的博客-CSDN博客https://blog.csdn.net/u013379032/article/details/131818865 事务 事务是一系列逻辑相关的数据库操作&#xff0c;可以作为一个整体进行操作或者回滚。事务通常会包含一个序列的读或者写操作&#xf…

Flink任务优化分享

Flink任务优化分享 1.背景介绍 线上计算任务在某版本上线之后发现每日的任务时长都需要三个多小时才能完成&#xff0c;计算时间超过了预估时间&#xff0c;通过Dolphinscheduler的每日调度任务看&#xff0c;在数据层 dwd 的数据分段任务存在严重的性能问题&#xff0c;每天…