当前位置: 首页 > web >正文

全面解析Java(上)------多线程编程:从线程生命周期到并发机制的深度剖析与实践指南

JAVA

Introduction:收纳技术相关的JAVA知识 JUCThreadLockI/O 等总结!

文章目录

  • Thread
    • 线程实现方式
    • 线程创建方式
    • 线程生命周期
      • 新建状态(NEW)
      • 可运行状态(RUNNABLE)
      • 被阻塞状态(BLOCKED)
      • 等待状态(WAITING)
      • 计时等待状态(TIMED_WAITING)
      • 已终止状态(TERMINATED)

Thread

什么是进程 ?

进程是资源分配的最小单位。(资源包括各种表格、内存空间、磁盘空间) 同一进程中的多条线程将共享该进程中的全部系统资源。

什么是线程 ?

线程是CPU调度的最小单位。线程只由相关堆栈(系统栈或用户栈)寄存器和线程控制表组成。 而寄存器可被用来存储线程内的局部变量。

什么是并行和并发 ?

  • 并行运行:总线程数≤CPU数量×核心数
  • 并发运行:总线程数>CPU数量×核心数(如:有的操作系统CPU线程切换之间用的时间片轮转进程调度算法)

线程优缺点

  • 优点

    • 创建一个新线程的代价要比创建一个新进程小的多
    • 线程之间的切换相较于进程之间的切换需要操作系统做的工作很少
    • 线程占用的资源要比进程少很多
    • 能充分利用多处理器的可并行数量
    • 等待慢速IO操作结束以后,程序可以继续执行其他的计算任务
    • 计算(CPU)密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
    • IO密集型应用,为了提高性能,将IO操作重叠,线程可以等待不同的IO操作
  • 缺点

    • 性能损失
    • 健壮性降低
    • 缺乏访问控制
    • 编程难度提高

线程实现方式

实现线程只有一种方式:

  • new Thread()

实现线程执行内容有两种方式:

  • 继续Thread类:Thread实现了Runable接口
  • 实现Runable接口:new Thread(new Runable(){……}),本质是通过Thread的run()进行调用触发

更多实现线程执行内容的方式,只需在此基础上进行封装:

  • 线程池创建线程:本质是通过 new Thread() 的方式实现
  • 有返回值的Callable创建线程:需要提交到线程池中执行。本质是通过实例化Thread的方式实现
  • 定时器Timer:本质是继承自 Thread 类实现

Thread、Runnable和Callable的区别

  • Runnable相对于Thread的优势是:避免单继承的局限,适合于资源共享场景
  • Thread使用JNI调用(native修饰的start0方法)系统函数来完成start,Runnable则由JVM来实现start,Callable也需要调用Thread.start()启动线程
  • 一般情况,多线程中优先选择实现Runnable接口
  • Callable能返回任务线程执行结果,而Runable不能返回
  • Callable的call方法允许抛出异常,而Runable异常只能在run方法内部消化

Thread.sleep(0)的作用是什么?

由于Java采用抢占式的线程调度算法,因此可能会出现某条线程常常获取到CPU控制权的情况,为了让某些优先级比较低的线程也能获取到CPU控制权,可以使用Thread.sleep(0)手动触发一次操作系统分配时间片的操作,这也是平衡CPU控制权的一种操作。

wait()和sleep()的区别?

  • wait()来自Object ,sleep()来自Thread
  • 调用wait()时线程会释放锁,调用sleep()时线程不会释放对象锁(只是暂时让出CPU的执行权)
  • wait()只能在同步控制方法或者同步控制块中使用,sleep()可以在任何地方使用
  • wait()可以通过notify()或notifyAll()被结束 ,sleep()只能等待休眠时间到期后才结束

线程创建方式

  • 继承Thread类
  • 实现Runnable接口
  • ExecutorService、Callable、Future有返回值线程
  • 基于线程池的方式

线程生命周期

Linux中线程状态一共有5种:

  • 初始状态(New):对应 Java中的 NEW 状态
  • 可运行状态(Ready):对应 Java中的 RUNNBALE 状态
  • 运行状态(Running):对应 Java中的 RUNNBALE 状态
  • 等待状态(Waiting):该状态在 Java中被划分为了 BLOCKEDWAITINGTIMED_WAITING 三种状态
  • 终止状态 (Terminated):对应 Java中的 TERMINATED 状态

Java中线程状态一共有6种(生命周期):

  • New(新创建):新创建了一个线程对象,但还没有调用start()方法
  • Runnable(可运行):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。线程对象创建后,其它线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)
  • Blocked(被阻塞):表示线程阻塞于锁
  • Waiting(等待):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)
  • Timed Waiting(计时等待):该状态不同于WAITING,它可以在指定的时间后自行返回
  • Terminated(被终止):表示该线程已经执行完毕。线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。在一个终止的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常

如果想要确定线程当前的状态,可以通过 getState() 方法,并且线程在任何时刻只可能处于 1 种状态。线程状态切换:

在这里插入图片描述

新建状态(NEW)

在这里插入图片描述

New 表示线程被创建但尚未启动的状态:当我们用 new Thread() 新建一个线程时,如果线程没有开始运行 start() 方法,所以也没有开始执行 run() 方法里面的代码,那么此时它的状态就是 New。而一旦线程调用了 start(),它的状态就会从 New 变成 Runnable,也就是状态转换图中中间的这个大方框里的内容。

可运行状态(RUNNABLE)

在这里插入图片描述

Java 中的 Runable 状态对应操作系统线程状态中的两种状态,分别是 Running 和 Ready,也就是说,Java 中处于 Runnable 状态的线程有可能正在执行,也有可能没有正在执行,正在等待被分配 CPU 资源。

所以,如果一个正在运行的线程是 Runnable 状态,当它运行到任务的一半时,执行该线程的 CPU 被调度去做其他事情,导致该线程暂时不运行,它的状态依然不变,还是 Runnable,因为它有可能随时被调度回来继续执行任务。

被阻塞状态(BLOCKED)

在这里插入图片描述

首先来看最简单的 Blocked,从箭头的流转方向可以看出,从 Runnable 状态进入 Blocked 状态只有一种可能,就是进入 synchronized 保护的代码时没有抢到 monitor 锁,无论是进入 synchronized 代码块,还是 synchronized 方法,都是一样。当处于 Blocked 的线程抢到 monitor 锁,就会从 Blocked 状态回到Runnable 状态。

等待状态(WAITING)

在这里插入图片描述

线程进入 Waiting 状态有三种可能性:

  • 没有设置 Timeout 参数的 Object.wait() 方法
  • 没有设置 Timeout 参数的 Thread.join() 方法
  • LockSupport.park() 方法

Blocked 仅仅针对 synchronized monitor 锁,可是在 Java 中还有很多其他的锁,比如 ReentrantLock,如果线程在获取这种锁时没有抢到该锁就会进入 Waiting 状态,因为本质上它执行了 LockSupport.park() 方法,所以会进入 Waiting 状态。同样,Object.wait() 和 Thread.join() 也会让线程进入 Waiting 状态。

Blocked 与 Waiting 的区别是 Blocked 在等待其他线程释放 monitor 锁,而 Waiting 则是在等待某个条件,比如 join 的线程执行完毕,或者是 notify()/notifyAll() 。

计时等待状态(TIMED_WAITING)

在这里插入图片描述

在 Waiting 上面是 Timed Waiting 状态,这两个状态是非常相似的,区别仅在于有没有时间限制,Timed Waiting 会等待超时,由系统自动唤醒,或者在超时前被唤醒信号唤醒。以下情况会让线程进入 Timed Waiting 状态。

  • 设置了时间参数的 Thread.sleep(long millis) 方法
  • 设置了时间参数的 Object.wait(long timeout) 方法
  • 设置了时间参数的 Thread.join(long millis) 方法
  • 设置了时间参数的 LockSupport.parkNanos(long nanos) 方法和 LockSupport.parkUntil(long deadline) 方法

已终止状态(TERMINATED)

在这里插入图片描述

线程会以下面三种方式结束,结束后就是终止状态:

  • 正常结束:run()或 call()方法执行完成,线程正常结束

  • 异常结束:线程抛出一个未捕获的 Exception 或 Error

  • 调用 stop:直接调用该线程的 stop()方法来结束该线程—该方法通常容易导致死锁,不推荐使用

http://www.xdnf.cn/news/2512.html

相关文章:

  • 组件的基本知识
  • 力扣hot100,739每日温度(单调栈)详解
  • 【Spring Boot】Maven中引入 springboot 相关依赖的方式
  • linux
  • Maven 使用教程
  • C语言复习笔记--内存函数
  • 土壤有机质含量
  • adb常用的20个命令
  • java_基础Java 转义字符学习笔记
  • Top-k问题的解法
  • 在线重定义——分区表改造
  • 收藏按钮变色问题
  • 18.电源滤波器的量化选型方法
  • IP地址如何切换到国内别的省份?一步步指导
  • 蓝桥杯 11. 打印大X
  • 设计模式每日硬核训练 Day 16:责任链模式(Chain of Responsibility Pattern)完整讲解与实战应用
  • 从零到精通:深入剖析GoFrame的gcache模块及其在项目中的实战应用
  • 实现 Babylon.js 鼠标输入管理单例 (MouseController) 的最佳实践
  • WebGIS面试题目整合资料
  • 分享!RASP的技术应用
  • 鸿蒙OSS文件(视频/图片)压缩上传组件-能够增删改查
  • 软件功能设计视角下的能源管理系统功能清单构建与实践​
  • 构建事件驱动的云原生后端系统 —— 从设计到实践
  • 多模态大语言模型arxiv论文略读(四十五)
  • 【数据结构_堆
  • 虚函数表的设计和多态的实现
  • 《AI大模型应知应会100篇》第38篇:大模型与知识图谱结合的应用模式
  • 计算机三大主流操作系统的前世今生 - Linux|macOS|Windows
  • 多商户 | 可二次开发【全开源】小程序源码商城挑选指南!
  • SQLMesh 测试自动化:提升数据工程效率