Java 并发编程知识总结【一】

news2024/11/15 11:09:00

JUC 是什么?

java.util.concurrent 在并发编程中使用的工具类

concurrent:并发

image-20221231111506601

1. 线程基础知识复习

1.1 进程(process)

进程是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生、存在和消亡的过程(生命周期)。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。

  • 如:运行中的QQ,运行中的MP3播放器
  • 程序是静态的,进程是动态的
  • 进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域

1.2 线程(thread)

线程(thread),进程可进一步细化为线程,是一个程序内部的一条执行路径。

  • 若一个进程同一时间并行执行多个线程,就是支持多线程的
  • 线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销小
  • 一个进程中的多个线程共享相同的内存单元/内存地址空间—>它们从同一堆中分配对象,可以访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源可能就会带来安全的隐患

1.3 管程

Monitor其实是一种同步机制,他的义务是保证(同一时间)只有一个线程可以访问被保护的数据和代码。

JVM中同步是基于进入和退出监视器对象(Monitor,管程对象)来实现的,每个对象实例都会有一个Monitor对象。

Object o = new Object();

new Thread(() -> {
    synchronized (o)
    {

    }
},"t1").start();

Monitor 对象会和 Java 对象一同创建并销毁,它底层是由 C++ 语言来实现的。

在 JVM 第3版中

image-20221231113143834

1.4 用户线程和守护线程

Java 线程分为用户线程和守护线程,线程的 daemon 属性为 true 表示是守护线程,false 表示是用户线程。

守护线程:是一种特殊的线程,在后台默默地完成一些系统性的服务,比如垃圾回收线程

用户线程:是系统的工作线程,它会完成这个程序需要完成的业务操作

public static void main(String[] args) {
    Thread t1 = new Thread(() -> {
        System.out.println(Thread.currentThread().getName() + "\t 开始运行," +
                           (Thread.currentThread().isDaemon() ? "守护线程" : "用户线程"));
        while (true) {

        }
    }, "t1");
    t1.start();
    // 3秒钟后主线程再运行
    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("----------main线程运行完毕");
}
 运行结果
t1	 开始运行,用户线程
----------main线程运行完毕
此时程序还在运行
public static void main(String[] args) {
    Thread t1 = new Thread(() -> {
        System.out.println(Thread.currentThread().getName() + "\t 开始运行," +
                           (Thread.currentThread().isDaemon() ? "守护线程" : "用户线程"));
        while (true) {

        }
    }, "t1");
    // 线程的 daemon 属性为 true 表示是守护线程,false 表示是用户线程
    t1.setDaemon(true);
    t1.start();
    // 3秒钟后主线程再运行
    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("----------main线程运行完毕");
}
 运行结果
t1	 开始运行,守护线程
----------main线程运行完毕
此时程序不再运行

结论(重点):

当程序中所有用户线程执行完毕之后,不管守护线程是否结束,系统都会自动退出;如果用户线程全部结束了,意味着程序需要完成的业务操作已经结束了,系统可以退出了。所以当系统只剩下守护进程的时候,java虚拟机会自动退出。

设置守护线程,需要在start()方法之前进行。

1.5 线程状态

public enum State {
    New,//新建
    Runnable,//就绪
    BLOCKED,//阻塞
    WAITING,//不见不散
    TIMED_WAITING,//过时不候
    TERMINATED//终结
}

线程的生命周期:

  • 新建: 当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
  • 就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件,只是没分配到CPU资源
  • 运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run()方法定义了线程的操作和功能
  • 阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出CPU并临时中止自己的执行,进入阻塞状态
  • 死亡:线程完成了它的全部工作或线程被提前强制性地中止或出现异常导致结束

1.6 sleep/wait的区别

一句话就是都是将当前线程暂停,但是 wait 放开手去睡,放开手里的锁,sleep 握紧手去睡,醒了手里还有锁。

  • sleep方法:是Thread类的静态方法,当前线程将睡眠n毫秒,线程进入阻塞状态。当睡眠时间到了,会解除阻塞,进行可运行状态,等待CPU的到来。睡眠不释放锁(如果有的话)
  • wait方法
    • 是Object 的方法
    • 在当前线程中调用方法: 对象名.wait()
    • 使当前线程进入等待(某对象)状态,直到另一线程对该对象发出notify (或notifyAll)为止
    • 调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)
    • 调用此方法后,当前线程将释放锁 ,然后进入等待
    • 在当前线程被notify后,要重新获得监控权,然后从断点处继续代码的执行

1.7 并发与并行

  • 并发:指两个或多个事件在同一个时间段内发生。(一个CPU(采用时间片)同时执行多个任务—秒杀、多个人做同一件事)
  • 并行:指两个或多个事件在同一时刻发生(同时发生)。(多个CPU同时执行多个任务—多个人同时做不同的事)

2. JUC 的辅助类

2.1 CountDownLatch 减少次数

案例:6个同学陆续离开教室后值班同学才可以关门。main主线程必须要等前面6个线程完成全部工作后,自己才能开干

for (int i = 1; i <= 6; i++) {
    new Thread(() -> SmallTool.printTimeAndThread("离开教室"), String.valueOf(i)).start();
}
SmallTool.printTimeAndThread("班长关门走人");
// 结果
1672477117075	|	24	|	1	|	离开教室
1672477117075	|	29	|	6	|	离开教室
1672477117075	|	25	|	2	|	离开教室
1672477117075	|	28	|	5	|	离开教室
1672477117075	|	1	|	main	|	班长关门走人
1672477117075	|	26	|	3	|	离开教室
1672477117075	|	27	|	4	|	离开教室

从上述代码中我们发现问题所在,开启的线程还未执行关闭,主线程就已经关闭了。

这个时候可以使用我们的 CountWownLatch 来进行解决。

是什么:允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助(就是减少到0时,开始执行某个任务)

CountDownLatch 主要有两个方法,当一个或多个线程调用 await 方法时,这些线程会阻塞。

其它线程调用 countDown 方法会将计数器减1(调用 countDown 方法的线程不会阻塞),

当计数器的值变为0时,因 await 方法阻塞的线程会被唤醒,继续执行。

改进代码:

public static void main(String[] args) throws InterruptedException {
    CountDownLatch countDownLatch = new CountDownLatch(6);
    for (int i = 1; i <= 6; i++) {
        new Thread(() -> {
            SmallTool.printTimeAndThread("离开教室");
            // 离开一个减少一个
            countDownLatch.countDown();
        }, String.valueOf(i)).start();
    }
    // 主线程进行等待 阻塞
    countDownLatch.await();
    SmallTool.printTimeAndThread("班长关门走人");
}
// 结果
1672477600285	|	25	|	2	|	离开教室
1672477600285	|	26	|	3	|	离开教室
1672477600285	|	27	|	4	|	离开教室
1672477600285	|	28	|	5	|	离开教室
1672477600285	|	29	|	6	|	离开教室
1672477600285	|	24	|	1	|	离开教室
1672477600285	|	1	|	main	|	班长关门走人

2.2 CyclicBarrier 循环栅栏

是什么:允许一组线程全部等待彼此达到共同屏障点的同步辅助(就是增加到一个值时候,开始执行某个任务)

原理:CyclicBarrier 的字面意思是可循环(Cyclic)使用的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。线程进入屏障通过CyclicBarrierawait() 方法

public static void main(String[] args) {
    CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> SmallTool.printTimeAndThread("*****召唤神龙"));

    for (int i = 1; i <= 7; i++) {
        final int tempInt = i;
        new Thread(() -> {
            SmallTool.printTimeAndThread("收集到" + tempInt + "星龙珠");
            try {
                cyclicBarrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                throw new RuntimeException(e);
            }
        }, String.valueOf(i)).start();
    }
}
// 结果
1672478173433	|	30	|	7	|	收集到7星龙珠
1672478173433	|	25	|	2	|	收集到2星龙珠
1672478173433	|	29	|	6	|	收集到6星龙珠
1672478173433	|	28	|	5	|	收集到5星龙珠
1672478173433	|	27	|	4	|	收集到4星龙珠
1672478173433	|	26	|	3	|	收集到3星龙珠
1672478173433	|	24	|	1	|	收集到1星龙珠
1672478173433	|	27	|	4	|	*****召唤神龙

2.3 Semaphore 信号灯

是什么:一个计数信号量。 在概念上,信号量维持一组许可证。 如果有必要,每个 acquire() 都会阻塞,直到许可证可用,然后才能使用它。 每个 release() 添加许可证,潜在地释放阻塞获取方法。 但是,没有使用实际的许可证对象; Semaphore 只保留可用数量的计数,并相应地执行。(就是当前的资源不够时,需要轮着获取,只能等前一个释放后,后一个才能获取)

原理:在信号量上我们定义两种操作:

  • acquire(获取)当一个线程调用 acquire 操作时,它要么通过成功获取信号量(信号量减1),要么一直等下去,直到有线程释放信号量,或超时。
  • release(释放)实际上会将信号量的值加1,然后唤醒等待的线程。

信号量主要用于两个目的,一个是用于多个共享资源的互斥使用,另一个用于并发线程数的控制

更多文章在我的语雀平台:https://www.yuque.com/ambition-bcpii/muziteng

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

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

相关文章

【数据集7】全球人类住区层GHSL数据详解

全球人类住区层Global Human Settlement Layer 官网地址-GHSL - Global Human Settlement Layer 1 全球人类住区层GHS-SMOD Global human settlement layer-settlement model grid (GHS-SMOD)&#xff1a;描述 epoch时段: 1975-2030年 5年一个周期resolution空间分辨率: …

Codeforces Round #833 (Div. 2)E. Yet Another Array Counting Problem(笛卡尔树+树形DP)

题目链接&#xff1a;Problem - E - Codeforces 样例输入&#xff1a; 4 3 3 1 3 2 4 2 2 2 2 2 6 9 6 9 6 9 6 9 9 100 10 40 20 20 100 60 80 60 60样例输出&#xff1a; 8 5 11880 351025663题意&#xff1a;给定一个长度为n的数组a[],对于每一个区间[l,r]&#xff0c;这个…

[Python从零到壹] 六十一.图像识别及经典案例篇之基于纹理背景和聚类算法的图像分割

祝大家新年快乐&#xff0c;阖家幸福&#xff0c;健康快乐&#xff01; 欢迎大家来到“Python从零到壹”&#xff0c;在这里我将分享约200篇Python系列文章&#xff0c;带大家一起去学习和玩耍&#xff0c;看看Python这个有趣的世界。所有文章都将结合案例、代码和作者的经验讲…

尚医通-查询删除科室接口-添加查询删除排班接口实现(二十)

目录&#xff1a; &#xff08;1&#xff09;数据接口-查询和删除科室接口-功能实现 &#xff08;2&#xff09;数据接口-排版接口-功能实现 &#xff08;1&#xff09;数据接口-查询和删除科室接口-功能实现 查看医院系统中查询科室的对应的方法 查询条件需要用的类&#…

【数据结构】链式存储:链表

目录 &#x1f947;一&#xff1a;初识链表 &#x1f392;二、链表的实现&#xff08;单向不带头非循环&#xff09; &#x1f4d8;1.创建节点类 &#x1f4d2;2.创建链表 &#x1f4d7;3.打印链表 &#x1f4d5;4.查找是否包含关键字key是否在单链表当中 &#x1f4d9;…

Webpack核心概念

1. 核⼼概念 Entry Entry ⽤来指定 webpack 的打包⼊⼝。 依赖图的⼊⼝是 entry&#xff0c;对于⾮代码⽐如图⽚、字体依赖也会不断加⼊到依赖图中。 Entry 的⽤法&#xff1a; 1. 单⼊⼝&#xff1a;entry 是⼀个字符串&#xff1b; module.exports {entry: ./path/to/my…

若依框架-补充篇:Vuex全局状态管理Axios二次封装

在上一篇《若依框架&#xff1a;前端登录组件与图像验证码|用户登录逻辑》中的篇末&#xff0c;对Vuex全局状态管理、Axios二次封装部分介绍的较为粗略&#xff0c;因此就有了这个补充篇。 目录 Vuex全局状态管理 Vuex是什么&#xff1f; 如何理解“状态管理模式”&#xf…

【Java语法】之String类练习1

目录 1.字符串中的第一个唯一字符 2. 最后一个单词的长度 58. 最后一个单词的长度 3.验证回文串 4.字符串相加 5.小结&#xff1a; 1.字符串中的第一个唯一字符387. 字符串中的第一个唯一字符https://leetcode.cn/problems/first-unique-character-in-a-string/ 给定一个字符…

【免费开放源码】审批类小程序项目实战(活动申请详解)

第一节&#xff1a;什么构成了微信小程序、创建一个自己的小程序 第二节&#xff1a;微信开发者工具使用教程 第三节&#xff1a;深入了解并掌握小程序核心组件 第四节&#xff1a;初始化云函数和数据库 第五节&#xff1a;云数据库的增删改查 第六节&#xff1a;项目大纲以及制…

Mac下安装go

1.下载地址 ​​​​​​https://golang.google.cn/dl/ 2.安装Go 3.查看安装效果 go version go env 4.安装vscode和插件 4.1.安装vscode https://code.visualstudio.com/Download 4.2.安装GO插件 4.3.设置goproxy 执行命令&#xff1a;vim ~/.bash_profile export GO1…

数值分布的分散程度对迭代次数的影响

( A, B )---1*30*2---( 1, 0 )( 0, 1 ) 让网络的输入只有1个节点&#xff0c;AB各由7张二值化的图片组成&#xff0c;排列组合A和B的所有可能性&#xff0c;固定收敛误差为7e-4&#xff0c;统计收敛迭代次数 1 2 3 4 5 6 7 迭代次数 1b 1b 1b 1b 1b 1b 0 0*0*0…

PHP---文件上传

目录 一、文件上传的概念 二、文件上传的步骤 &#xff08;1&#xff09;表单的制作 三、$_FILES详解 &#xff08;1&#xff09;name &#xff08;2&#xff09;tmp_name &#xff08;3&#xff09;type &#xff08;4&#xff09;error &#xff08;5&#xff09;si…

YOLO v6:一个硬件友好的目标检测算法

本文来自公众号“AI大道理” YOLOv6 是美团视觉智能部研发的一款目标检测框架&#xff0c;致力于工业应用。 YOLOv6支持模型训练、推理及多平台部署等全链条的工业应用需求&#xff0c;并在网络结构、训练策略等算法层面进行了多项改进和优化&#xff0c;在 COCO 数据集上&…

一文轻松明白 Base64 编码原理

把图片丢进浏览器&#xff0c;打开sources能看到一长串字符串&#xff0c;这是图片的Base64编码。这一长串编码到底是怎么生成的呢&#xff1f; 我们接下来探索一下base64编码的原理 Base64 名称的由来 Base64编码要求把3个8位的字节&#xff08;3824&#xff09;转化为4个6…

C++代码编程学习(2):类和对象封装部分的两个案例-立方体与点圆位置

C类与对象 封装的学习 挺有趣的&#xff01; 一、前言 昨日有点事忙了些&#xff0c;今天把昨天学习的两个案例给整理一下&#xff0c;C确实比较原始基础&#xff0c;在学习过程中需要好好总结分析与记录。 二、效果展示 案例一&#xff1a;设计立方体 立方体的面积和体积 用…

阿里微服务质量保障系列(一):微服务知多少

年初买了一本集团巨佬联合出的书《阿里测试之道》&#xff0c;然后认真拜读了下&#xff0c;我相信看过的同学都会获益匪浅&#xff0c;此书分享了阿里在大促保障、移动App测试、大数据测试、AI系统测试、云计算测试、资损防控、物流类测试等领域的方法、技术和工具平台&#x…

十一、Properties、多线程

Properties集合 Properties作为Map集合的使用 介绍 是一个Map体系的集合类Properties可以保存到流中或从流中加载属性列表中的每个键及其对应的值都是一个字符串 基本使用 public static void main(String[] args) {Properties prop new Properties();//增prop.put("…

Pytorch c++ 部署报错解决方案

目录 1. Only the versions between 2017 and 2019 (inclusive) are supported! 2. Cannot find cuDNN library. Turning the option off C 部署的时候&#xff0c;demo 写完之后&#xff0c;提示如下错误 1. Only the versions between 2017 and 2019 (inclusive) are sup…

使用Kubernetes部署xxl-job-admin及xxl-job执行器服务

部署环境 xxl-job-2.4.0kubernetes-1.26 这里以xxl-job官方的2.4.0的代码为例子&#xff0c;在官方编写的Dockerfile基础上使用dockerkubernetes进行部署&#xff0c;xxl-job-admin和执行器的Dockerfile、application等配置文件并不是关键&#xff0c;所以这里示例安装以官方…

Linux系统初始化进程及文件(带命令)

作者简介&#xff1a;一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.系统初始化进程及文件 1.init 进程 2.Systemd概述 3.SysVi…