Java并发编程(一)多线程基础概念

概述

  • 多线程技术:基于软件或者硬件实现多个线程并发执行的技术

    • 线程可以理解为轻量级进程,切换开销远远小于进程

    • 在多核CPU的计算机下,使用多线程可以更好的利用计算机资源从而提高计算机利用率和效率来应对现如今的高并发网络环境

  • 并发编程核心三要素
    • 原子性
      • 原子,即一个不可再被分割的颗粒。在Java中原子性指的是一个或多个操作要么全部执行成功要么全部执行失败
    • 有序性
      • 程序执行的顺序按照代码的先后顺序执行。(处理器可能会对指令进行重排序)
    • 可见性
      • 当多个线程访问内存中同一个变量时,如果其中一个线程对其作了修改,其他线程能立即获取到最新的值
  • 并行 VS 并发
    • 并行:在同一时刻,有多个指令在多个CPU上同时执行

    • 并发:在同一时刻,有多个指令在单个CPU上交替执行

  • 同步 VS 异步 && 阻塞 VS 非阻塞

    同步和异步指的对于消息结果的获取是客户端(调用者)主动获取[同步],还是由服务端(提供者)主动通知客户端[异步];阻塞和非阻塞指的一个是客户端(调用者)等待消息处理时的本身状态是挂起[阻塞]还是继续处理其他事[非阻塞];

    • 同步阻塞:客户端主动发起获取结果,而同时一直在等待应答结果
    • 同步非阻塞:客户端主动发起获取结果,而同时不断轮询查看发起的请求是否有应答结果
    • 异步阻塞:客户端发出请求后,服务端会主动通知,而客户端同时一直在等待通知
    • 异步非阻塞:客户端发出请求后,服务端会主动通知,而客户端在获取服务端通知之前已经去处理其他事情
  • 进程 VS 线程
    • 进程:是系统运行的基本单位
      • 独立性: 进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位
      • 动态性: 进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的
      • 并发性: 任何进程都可以同其他进程一起并发执行
    • 线程:是进程中的单个顺序控制流,是一条执行路径
      • 单线程: 一个进程如果只有一条执行路径,则称为单线程程序
      • 多线程: 一个进程如果有多条执行路径,则称为多线程程序
  • 悲观锁 VS 乐观锁
    • 悲观锁: 每次操作都会加锁,会造成线程阻塞
    • 乐观锁: 每次操作不加锁而是假设没有冲突而去完成某项操作,若因为冲突导致失败就重试,直到成功为止,不会造成阻塞
  • 线程安全

    线程安全问题指的是内存的安全,在每个进程的内存空间中都会有一块共享区域称为堆内存,进程内的所有线程都可以访问到该区域,这就是造成线程安全问题的潜在原因。所以在堆内存中的数据由于可以被任何线程访问到,在没有限制的情况下存储在内存的数据(主要是全局变量和静态变量)可能被别的线程修改。因此在多线程场景下,我们需要通过相关限制实现线程安全

  • 上下文切换:线程在执行过程中都会有自己的运行条件和状态,这些运行条件和状态我们就称之为线程上下文,这些信息例如程序计数器、虚拟机栈、本地方法栈等信息。当出现以下几种情况时线程就会从占用CPU状态中退出:

    • 线程主动让出CPU,例如调用wait或者sleep等方法
    • 线程的CPU 时间片用完 而退出CPU占用状态 (因为操作系统为了避免某些线程独占CPU导致其他线程饥饿的情况就设定的例如时间分片算法)
    • 线程调用了阻塞类型的系统中断,例如IO请求等
    • 线程被终止或者结束运行
    • 上述的前三种情况都会发生上下文切换为了保证线程被切换在恢复时能够继续执行,所以上下文切换都需要保存线程当前执行的信息,并恢复下一个要执行线程的现场。所以会占用CPU和内存资源,频繁的进行上下文切换就会导致整体效率低下
  • 死锁:指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。死锁的必要条件包括
    • 互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用
    • 请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放
    • 不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放
    • 环路等待条件:在发生死锁时,必然存在一个进程--资源的环形链

线程分类

  • 普通线程:即前台线程或者用户线程;即应用程序运行的线程
  • 守护线程:即服务线程或者后台线程;优先级较低,作用是为其他线程的运行提供便利服务
    • JRE判断程序是否执行结束的标准是所有的前台执行线程执行完毕,而不管后台线程(守护线程)的状态
    • 守护线程最典型的应用就是GC
    • 除虚拟机提供的如GC守护线程外,开发者也可以设置线程为守护线程

线程生命周期(线程状态)

根据sun官网可知,线程生命周期在java中有以下几种状态:初始(NEW) ,可运行(RUNNABLE)运行(Running),阻塞(BLOCKED)终止(TERMINATED)

  • 初始(NEW): 如果创建Thread类的实例但在调用start()方法之前,线程处于初始(NEW)状态。
  • 可运行(RUNNABLE): 调用start()方法后,线程处于runnable状态,但线程调度程序尚未选择它作为正在运行的线程
  • 运行(RUNNING): 如果线程调度程序已选择它,则线程处于运行状态
  • 阻塞(BLOCKED): 此时线程仍处于活动状态但当前没有资格运行的状态
  • 终止(TERMINATED): 当run()方法退出时,线程处于终止或死亡状态

线程间通信方式

很多业务场景下某个任务都是通过多个线程一起完成,此时就需要线程之间进行通信一起完成该任务,线程通信就是当多个线程共同操作共享的资源时,互相告知自己的状态以避免资源争夺;线程通信主要可以分为三种方式,分别为共享内存、消息传递和管道流

  • 共享内存:线程之间共享程序的公共状态,线程之间通过读-写内存中的公共状态来隐式通信
    • volatile关键字,该方式是最简单的一种实现方式,volatile修饰的变量是共享内存,保证内存可见性,让多个线程共享一个标志位,当标志位更改的时候就执行不同的线程
  • 消息传递:线程之间没有公共的状态,线程之间必须通过明确的发送信息来显示的进行通信
    • Object类的 wait/notify方法,执行wait()方法,该线程释放锁资源,然后执行notify() 方法,唤醒其他的线程
    • condition类的 await/signal方法,condition通过lock对象创建,await操作会立刻释放掉锁,进入阻塞状态,signal会唤醒等待队列中的头节点(失败就依次唤醒)
  • 管道流: 管道的输入和输出实际上使用的是一个循环缓冲数组来实现的

创建线程

  • 通过继承Thread,重写其中的run方法,通过调用start方法启动线程时
  • 通过实现Runnable接口,重写其中的run方法,并将自定义类的实例作为一个参数传入Thread获取线程实例,再调用start方法启动线程
  • 通过实现callable接口的,重写其中的call方法。新建Callable的实例,将Callable传入FutureTask得到FutureTask实例,再将FutureTask实例传入Thread获得Thread实例,调用Thread的start方法启动线程,并通过FutureTask的get方法来获取返回值
  • 通过线程池提前为我们准备好线程,我们需要的时候直接取用就可以了,而不需要自己创建

线程Thread常用API

  • start():在使用 new 关键字创建一个线程后(New 状态),只有在 start() 方法执行后,才表示这个线程可运行了(Runnable 状态),至于何时真正运行还要看线程调度器的调度;在线程死亡后,不要再次调用 start() 方法。只能对新建状态的线程调用且只能调用一次 start() 方法,否则将抛出 IllegalThreadStateException 异常
  • run():启动线程是 start() 方法,而不是 run() 方法。如果直接调用 run() 方法,这个线程中的代码会被立即执行,多个线程就无法并发执行了
  • join():等待该线程完成的方法,其他线程将进入等待状态(Waiting 状态),通常由使用线程的程序(线程)调用,如将一个大问题分割为许多小问题,要等待所有的小问题处理后,再进行下一步操作
  • sleep():主动放弃占用的处理器资源,该线程进入阻塞状态(Blocked 状态),指定的睡眠时间超时后,线程进入就绪状态(Runnable),等待线程调度器的调用。
  • yield():主动放弃占用的处理器资源,线程直接进入就绪状态(Runnable),等待线程调度器的调用。可能出现当线程使用yield方法放弃执行后,线程调度器又将该线程调度执行
  • interrupt():没有任何强制线程终止的方法,这个方法只是请求线程终止,这个方法并没有实际的用途,还有 isInterrupted() 方法检查线程是否被中断
  • setDaemon():设置守护进程,该方法必须在 start() 方法之前调用,判断一个线程是不是守护线程,可以使用 isDaemon() 方法判断
  • setPriority():设置线程的优先级,理论上讲线程优先级高更容易被执行。每个线程默认的优先级和父线程(如 main 线程、普通优先级)的优先级相同,线程优先级区间为 1~10,三个静态变量:MIN_PRIORITY = 1、NORM_PRIORITY = 5、MAX_PRIORITY = 10。使用 getPriority() 方法可以查看线程的优先级
  • isAlive():检查线程是否处于活动状态,如果线程处于就绪、运行、阻塞状态,方法返回 true,如果线程处于新建和死亡状态,方法返回 false

线程常见问题

sleep VS wait

  • sleep不会释放锁,只是单纯休眠一会,在给定时间后就会苏醒;而wait则会释放锁,若wait没有设定时间,只能通过notify或者notifyAll唤醒
  • wait常用于线程之间的通信或者交互,而sleep单纯让线程让出执行权。
  • sleep是Thread的方法,因为sleep要做的仅仅是让线程休眠,所以不涉及任何锁释放等逻辑,放在Thread上最合适;而wait是Object的方法,调用wait时会释放锁,并让对象进入WAITING状态,会涉及到资源释放等问题,所以我们需要将wait放在Object 类上

run VS start

  • run: 仅仅是方法,若直接通过对象调用run方法,那么该方法和普通方法没有任何差别,它仅仅是一个名字为run的普通方法
  • start: 开启线程方法,线程就会从用户态转内核态创建线程,并在获取CPU时间片的时候开始运行,然后运行run方法

Thread,Runnable,Callable区别

  • Thread 和 Runnable 区别
    • Thread 是类,而Runnable是接口;如果有其他类需要继承的话肯定是用Runnable接口了
    • Thread本身是实现了Runnable接口的类。我们知道“一个类只能有一个父类,但是却能实现多个接口”,因此Runnable具有更好的扩展性
  • Callable和Runnable区别
    • 相同点
      • 都是接口实现,具有良好的扩展性
    • 不同点
      • Callable可以在任务结束的时候提供一个返回值,Runnable无法提供这个功能
      • Callable的call方法可以抛出异常,而Runnable的run方法不能抛出异常

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++代码生成静态LIB链接库及其调用方法

1、在进行C代码移植时可将CPP文件封装为静态lib链接库,本文章讲述了如何将cpp文件封装为lib文件。 2、假设有文件a.cpp、a.h、b.cpp、b.h以及main.cpp,假设main调用了b,b调用了a。现在需要将a.cpp以及b.cpp封装为a.lib以及b.lib。 3、在VS2…

RISC-V公测平台发布 · UnixBench完整测试

简介 UnixBench是一个开源的GPLv2许可的工具,它提供了对类Unix系统性能的基本指标。 通过运行UnixBench,可以获得有关系统性能的基本指标,用于与其他系统进行比较,也可以作为改进系统性能的参考。但UnixBench并不是一个综合性能…

MySQL和钉钉单据接口对接

MySQL和钉钉单据接口对接 数据源系统:钉钉 钉钉(DingTalk)是阿里巴巴集团打造的企业级智能移动办公平台,是数字经济时代的企业组织协同办公和应用开发平台。钉钉将IM即时沟通、钉钉文档、钉闪会、钉盘、Teambition、OA审批、智能人事、钉工牌…

【iOS】RunLoop

前言-什么是RunLoop? 什么是RunLoop? 跑圈?字面上理解确实是这样的。 Apple官方文档这样解释RunLoop RunLoop是与线程息息相关的基本结构的一部分。RunLoop是一个调度任务和处理任务的事件循环。RunLoop的目的是为了在有工作的时候让线程忙起来&#…

基于Echarts的大数据可视化模板:智慧物流管理

目录 引言物流管理的重要性大数据可视化在解决物流管理挑战中的作用智慧物流概述定义智慧物流的概念和特点智慧物流的关键技术和平台风险管理和预测:交通拥堵情况和风险预警Echarts与大数据可视化Echarts库以及其在大数据可视化领域的应用优势开发过程和所选设计方案模板如何满…

动手学深度学习Pytorch 4.4练习

1.这个多项式回归问题可以准确地解出吗?提⽰:使⽤线性代数。 可以,把多项式问题,用matlab的str2sym表示出来,再用solve求解。 2.考虑多项式的模型选择。 1. 绘制训练损失与模型复杂度(多项式的阶数)的关系…

关于在c++中使用数组名作为函数参数,或者使用数组名的地址作为函数参数问题的一些研究

前言 使用数组名作为函数参数&#xff0c;或者使用数组名的地址作为函数参数&#xff0c;常常出现于对于字符串的读入问题之中。 常有以下两种写法&#xff1a; 这是使用数组名作为函数参数 #include<cstdio> char s[100]; int main() {scanf("%s",s); }在…

抖音商品上架有攻略:详细介绍步骤与注意事项

抖音是一款非常流行的短视频分享平台&#xff0c;也是一个非常适合进行商品销售的平台。上架商品是在抖音上进行电商销售的重要一环&#xff0c;下面不若与众将介绍抖音商品的上架流程和注意事项。 1. 注册账号和认证&#xff1a;首先&#xff0c;你需要在抖音平台上注册一个账…

MYSQL06高级_为什么使用索引、优缺点、索引的设计、方案、聚簇索引、联合索引、注意事项

文章目录 ①. 为什么使用索引②. 索引及其优缺点③. InnoDb - 索引的设计④. InnoDb中的索引方案⑤. 索引 - 聚簇索引⑥. 索引 - 二级索引⑦. B树索引的注意事项⑧. MyISAM中索引方案 ①. 为什么使用索引 ①. 索引是存储引擎用于快速找到数据记录的一种数据结构,就好比去图书馆…

图像 检测 - RetinaNet: Focal Loss for Dense Object Detection (arXiv 2018)

图像 检测 - RetinaNet: Focal Loss for Dense Object Detection - 密集目标检测中的焦点损失&#xff08;arXiv 2018&#xff09; 摘要1. 引言2. 相关工作3. 焦点损失3.1 平衡交叉熵3.2 焦点损失定义3.3 类别不平衡与模型初始化3.4 类别不平衡和两级检测器 4. RetinaNet检测器…

Springboot中使用过滤器校验PSOT类型请求参数内容

目录 目的 实现步骤 完整代码 目的 在Springboot中创建过滤器&#xff0c;用来过滤所有POST类型请求并获取body中的参数进行校验内容是否合法&#xff1b;该方法仅适用于POST类型请求&#xff0c;因为POST和GET请求的参数位置不一样所以处理方式也不一样&#xff0c;如果想要…

flutter 没有open android module in Android studio 插件代码爆红

参考 1.结论 其实就是缺少这个文件 2.解决方案有两个 2.1 方案一 手动创建一个,命名规则是项目名字‘_android’‘.iml’ 内容如下: <?xml version"1.0" encoding"UTF-8"?> <module type"JAVA_MODULE" version"4">&l…

IoTDB在springboot2中的(二) 查询

上一章我们处理的基本的构建接入&#xff0c;以及插入的处理&#xff0c;那么接下来我们进行查询的操作处理。 我们继续在IoTDBSessionConfig工具类中加入查询的方法处理 /*** description: 根据SQL查询最新一条数据* author:zgy* param sql sql查询语句&#xff0c;count查询…

基于Java开发的企业级数字化采购系统

一、项目介绍 一款全源码可二开&#xff0c;可基于云部署、私有部署的企业级数字化采购管理系统&#xff0c;供应商全生命周期管控&#xff0c;公开询价管理&#xff0c;招标&#xff0c;定标&#xff0c;评审&#xff0c;生成订单&#xff0c;送货&#xff0c;收货全流程管理…

(十一)大数据实战——hadoop高可用之HDFS手动模式高可用

前言 本节内容我们介绍一下hadoop在手动模式下如何实现HDFS的高可用&#xff0c;HDFS的高可用功能是通过配置多个 NameNodes(Active/Standby)实现在集群中对 NameNode 的热备来解决上述问题。如果出现故障&#xff0c;如机器崩溃或机器需要升级维护&#xff0c;这时可通过此种…

【perl】报错合集

perl报错合集 &#xff08;注&#xff1a;可能会不定时更新&#xff09; 1.Name “main::x” used only once: possible typo at … 1.Name "main::x" used only once: possible typo at ...给某个变量赋值但是从来没有用它&#xff0c;或者变量之只用一次但没有…

Nginx(1)

目录 1.Nginx概述2.Nginx的特点3.Nginx主要功能1.反向代理2.负载均衡 1.Nginx概述 Nginx (engine x) 是一个自由的、开源的、高性能的HTTP服务器和反向代理服务器&#xff0c;也是一个IMAP、POP3、SMTP代理服务器。 Nginx是一个强大的web服务器软件&#xff0c;用于处理高并发…

仅使用 CSS 创建打字机动画效果

创建打字机效果比您想象的要容易。虽然实现这种效果的最常见方法是使用 JavaScript&#xff0c;但我们也可以使用纯 CSS 来创建我们的打字机动画。 在本文中&#xff0c;我们将了解如何仅使用 CSS 创建打字机动画效果。它简单、漂亮、容易。我们还将看看使用 CSS 与 JavaScrip…

百度资深PMO阚洁受邀为第十二届中国PMO大会演讲嘉宾

百度在线网络技术&#xff08;北京&#xff09;有限公司资深PMO阚洁女士受邀为由PMO评论主办的2023第十二届中国PMO大会演讲嘉宾&#xff0c;演讲议题&#xff1a;运筹于股掌之间&#xff0c;决胜于千里之外 —— 360斡旋项目干系人。大会将于8月12-13日在北京举办&#xff0c;…

大模型开发(十六):从0到1构建一个高度自动化的AI项目开发流程(中)

全文共1w余字&#xff0c;预计阅读时间约40~60分钟 | 满满干货(附代码)&#xff0c;建议收藏&#xff01; 本文目标&#xff1a;通过LtM提示流程实现自动构建符合要求的函数&#xff0c;并通过实验逐步完整测试code_generate函数功能。 代码下载点这里 一、介绍 此篇文章为…