2023年Java核心技术第十篇(篇篇万字精讲)

目录

十九 . 一个线程两次调用start()方法会出现什么情况?线程的生命周期和状态转移。

19.1 典型回答

19.1.1 线程生命周期:

19.1.2 计时等待详细解释:

 19.2 深入扩展考察

19.2.1 线程是什么?

19.2.2 Green Thread详细解释:

二十. Java程序产生死锁的情况以及如何进行定位,修复?

20.1 典型回答

20.1.1 定位死锁

20.1.1 .1 详细解释:


十九 . 一个线程两次调用start()方法会出现什么情况?线程的生命周期和状态转移。

线程是Java并发的基础元素。理解,操纵线程是必备技能。

19.1 典型回答

Java线程是不允许启动2次的,第二次调用必然会抛出illegalThreadStateException,运行时异常,多次调用start()被认为编程错误。

19.1.1 线程生命周期:

线程状态被明确定义在其公告内部枚举类型java.lang.Thread.State中:

分别是:

1. 新建(new):

表示线程被创建出来还没有真正启动的状态,可以认为是一个Java内部状态。

2. 就绪(runnable):

表示该线程已经在JVM中执行,当然由于执行需要计算资源,它可能是正在运行,也可能是还在等待系统分配给它CPU片段,在就绪队列里面排队。

3. 阻塞(blocked)

状态和讲的同步相关,阻塞表示线程在等待Monitor lock 。

如:

线程试图通过synchronized去获取某个锁,但是其他线程已经独占了,就会导致阻塞问题,使得线程处于阻塞状态。

4. 等待(waiting)

表示正在等待其他线程采取某些操作,

场景:类似生产者消费者模式,发现任务条件并没有满足,会让当前消费者线程等待(wait),另外的生产者线程去准备任务数据,然后通过类似notify等动作,通知消费者继续工作。

Thread.join()也会令线程进入等待状态。

5. 计时等待(timed_wait)

进入条件和等待状态类似,但是调用的是存在超时条件方法,比如wait或join等方法的指定超时版本。

6. 终止(terminated):

不管是意外退出还是正常执行结束,线程已经完成使命,终止运行。

当我们进行第二次调用start()方法的时候,线程可能处于终止或者其他(非new)状态,但是无论如何,都是不可以再次启动的。

19.1.2 计时等待详细解释:

当一个线程等待其他线程完成某个任务,并设置了超时时间,可以使用timed_wait方法。

public class TimedWaitExample {private boolean isTaskComplete = false;public synchronized void waitForTask() {try {// 设置等待超时时间为5秒wait(5000);if (!isTaskComplete) {System.out.println("任务未能在指定时间内完成,继续执行其他操作");}} catch (InterruptedException e) {e.printStackTrace();}}public synchronized void completeTask() {// 模拟任务完成try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}isTaskComplete = true;notifyAll();}public static void main(String[] args) {TimedWaitExample example = new TimedWaitExample();// 创建等待任务的线程Thread waitThread = new Thread(() -> {example.waitForTask();});// 创建完成任务的线程Thread completeThread = new Thread(() -> {example.completeTask();});// 启动线程waitThread.start();completeThread.start();try {// 等待两个线程执行完成waitThread.join();completeThread.join();} catch (InterruptedException e) {e.printStackTrace();}}
}

TimedWaitExample类包含了一个waitForTask方法和一个completeTask方法。在waitForTask方法中,调用了带有超时参数的wait方法,等待任务完成或超过5秒的时间限制。在completeTask方法中,模拟了任务的完成,并通过notifyAll方法唤醒处于等待状态的线程。

main方法中,创建了一个等待任务的线程和一个完成任务的线程,并启动它们。然后,使用join方法等待两个线程执行完成。

如果完成任务的线程在5秒内完成了任务,则等待线程会被唤醒并继续执行。如果任务未能在指定时间内完成,等待线程会输出一条提示信息并继续执行其他操作。

例子展示了如何使用timed_wait方法来实现线程等待超时的功能。

 19.2 深入扩展考察

面试热身题,进行对基本状态的简单的流转进行介绍,对线程进行理解是对我们日常开发和诊断分析有很大的帮助,都是必备的基础。

作为突破口,进行从各个不同的角度考察你对线程的掌握。

19.2.1 线程是什么?

操作系统的角度,我们可以简单的认为,线程是系统调度的最小单元,一个进程可以包含多个线程,作为任务真正运作者,有自己的栈(Stack),寄存器(Register),本地存储(Thread Local)等,但是会和进程内其他线程共享描述符,虚拟地址空间等。

具体实现中,线程分为内核线程,用户线程,Java的线程实现其实是与虚拟机相关的。

对于我们最熟悉的JDk,线程也进行了一个演进过程,基本上在Java 1.2 后,JDK已经抛弃了Green Thread,也就是用户调度的线程,现在的模型是一对一映射到操作系统内核线程。

19.2.2 Green Thread详细解释:

Green Thread模型的设计初衷是为了使Java程序能够在不依赖底层操作系统的情况下运行,并具备跨平台的能力。在Green Thread模型中,Java虚拟机自己实现了对线程的调度和管理,而不是依赖于底层操作系统的线程支持。

然而,由于Green Thread模型没有直接与操作系统内核进行交互,因此导致了一些限制和问题:

  1. 无法充分利用多核处理器的性能:由于Green Thread模型的线程调度和管理是由Java虚拟机自己完成的,它无法直接利用多核处理器的并行计算能力。在这种模型下,即使在具有多个物理核心的处理器上运行Java程序,所有的线程仍然只能通过单个物理核心来执行,不能实现真正的并行计算。

  2. 无法与底层操作系统进行充分的集成:Green Thread模型无法直接与底层操作系统进行交互,因此无法充分利用操作系统提供的各种线程调度算法和特性。

  3. 对资源的占用较大:由于Green Thread模型需要自己实现线程调度和管理,它需要占用较多的内存资源。每个Green Thread都需要分配一定的堆栈空间,而且它们的调度算法和状态维护也需要一定的计算和存储开销。

为了克服这些限制和问题,从Java 1.2版本开始,JDK采用了一对一映射到操作系统内核线程的模型,也称为"native thread"模型。这种模型能够更好地利用多核处理器的性能,并与底层操作系统进行充分的集成,提供更高效和可靠的线程支持。

Green Thread模型在提供跨平台能力方面具有优势,但无法充分利用多核处理器并与底层操作系统进行充分的集成。因此,JDK在Java 1.2之后放弃了Green Thread模型,转而使用一对一映射到操作系统内核线程的模型,以提供更强大和高效的线程支持。

二十. Java程序产生死锁的情况以及如何进行定位,修复?

20.1 典型回答

死锁是一种特定的程序状态,在实体之间,由于循环依赖导致彼此一直处于等待中,没有任何个体可以继续前进。

死锁不仅仅是在线程之间会发生,存在资源独占的进程之间同样也可能出现死锁。

通常来说,我们大多是聚焦在多线程场景中的死锁,指两个或多个线程之间,由于互相持有对方需要的锁,

20.1.1 定位死锁

定位死锁最常见的方式就是利用jstack工具获取线程栈,然后定位互相之间的依赖关系,进而找到死锁,如果是明细的死锁,我们可以通过jstack进行定位。

程序运行发生死锁后,绝大多数情况,无法在线进行解决,只能进行重启,修正程序本身的问题。

20.1.1 .1 详细解释:

当程序发生死锁时,通常情况下无法立即在运行时解决它,因为死锁是由于线程之间的资源竞争导致的相互等待,形成了一个循环依赖的状态。

死锁通常发生在多个线程同时请求一组共享资源,并且每个线程都持有一部分资源并等待其他线程释放它们所需的资源。当发生这种情况时,没有任何一个线程能够继续执行下去,它们被阻塞在等待资源释放的状态中,从而导致程序无法继续正常执行。

解决死锁问题需要针对程序本身进行修正,以消除或避免死锁的产生。以下是一些常见的方法:

  1. 分析和检测死锁:使用工具或技术来分析和检测死锁。例如,通过线程转储分析工具(如jstack)、死锁检测工具(如Java自带的jconsole、VisualVM或第三方工具)来查看线程的状态和死锁信息。

  2. 梳理锁的获取顺序:确保线程获取锁的顺序是一致的,避免出现循环依赖的情况。例如,如果线程A先获取锁1,再获取锁2,那么其他线程也应该按照相同的顺序获取这两个锁。这种预防措施可以减少死锁的发生。

  3. 避免长时间持有锁:尽量减少在持有锁的情况下进行耗时的操作,比如I/O操作或者远程调用。可以使用异步操作或者将操作拆分为更小的单元,以便在持有锁期间减少执行时间。

  4. 使用超时机制:在获取锁时设置一个超时时间,在等待超过一定时间后放弃获取锁并采取相应的处理策略。这可以避免线程无限期地等待锁而导致死锁。

  5. 死锁恢复策略:当检测到死锁时,程序可以采取恢复策略,例如释放已经获得的锁并回退一些操作,然后重新尝试执行。这个策略需要根据具体的业务场景来设计和实现。

尽管有以上的方法来预防和解决死锁问题,但有时候死锁发生的原因非常复杂,可能需要对程序进行彻底的重构才能解决。在这种情况下,重新启动程序是一种常见的解决方法,因为它可以清除死锁并重新开始执行。

总结起来,当程序发生死锁时,无法在线进行解决的大多数情况下需要重启程序,并通过修正程序本身的问题来避免死锁的再次发生。这涉及到分析和检测死锁、优化锁的获取顺序、避免长时间持有锁、使用超时机制以及实施死锁恢复策略等方法。

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

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

相关文章

【juc】读写锁ReentrantReadWriteLock

目录 一、说明二、读读不互斥2.1 代码示例2.2 截图示例 三、读写互斥3.1 代码示例3.2 截图示例 四、写写互斥4.1 代码示例4.2 截图示例 五、注意事项5.2.1 代码示例5.2.2 截图示例 一、说明 1.当读操作远远高于写操作时,使用读写锁让读读可以并发,来提高…

网络编程day1——进程间通信-socket套接字

基本特征:socket是一种接口技术,被抽象了一种文件操作,可以让同一计算机中的不同进程之间通信,也可以让不同计算机中的进程之间通信(网络通信) 本地进程间通信编程模型: 进程A …

IDEA遇到 git pull 冲突的几种解决方法

1 忽略本地修改,强制拉取远程到本地 主要是项目中的文档目录,看的时候可能多了些标注,现在远程文档更新,本地的版本已无用,可以强拉 git fetch --all git reset --hard origin/dev git pull关于commit和pull的先后顺…

亚马逊鲲鹏系统是怎么操作测评的

亚马逊鲲鹏系统可以注册亚马逊买家号、养号、下单留评等,是一款功能比较齐全的测评软件,具体操作如下: 首先我们需要先准备好买家账号,账号可以直接去购买已经注册好了的账号,也可以准备好账号所需要的一些邮箱、ip、…

无门槛访问ChatGPT升级版-数据指北AI

大家好,我是脚丫先生 (o^^o) 给小伙伴们介绍ChatGPT升级版不需要任何门槛,不需要单独搞账号,只要邮箱登录的方式,即可访问平台,以用户体验为首要,让所有人都能无门槛的使用目前市面上最强大的AI智能聊天&a…

Rn实现省市区三级联动

省市区三级联动选择是个很频繁的需求,但是查看了市面上很多插件不是太老不维护就是不满足需求,就试着实现一个 这个功能无任何依赖插件 功能略简单,但能实现需求 核心代码也尽力控制在了60行左右 pca-code.json树型数据来源 Administrative-d…

液体神经网络LLN:通过动态信息流彻底改变人工智能

巴乌米克泰吉 一、说明 在在人工智能领域,神经网络已被证明是解决复杂问题的非常强大的工具。多年来,研究人员不断寻求创新方法来提高其性能并扩展其能力。其中一种方法是液体神经网络(LNN)的概念,这是一个利用动态计算…

07:STM32----ADC模数转化器

目录 1:简历 2:逐次逼近型ADC 3:ADC基本结构 4:输入通道 5:规则组的4种转换模式 1:单次转化,非扫描模式 2:连续转化,非扫描模式 3:单次转化,扫描模式 4:单次转化,扫描模式 6:触发控制 7:数据对齐 8:转化时间 9:校准 10:ADC的硬件电路 A: AD单通道 1:连接图 2:函…

Git小白入门——了解分布式版本管理和安装

Git是什么? Git是目前世界上最先进的分布式版本控制系统(没有之一) 什么是版本控制系统? 程序员开发过程中,对于每次开发对各种文件的修改、增加、删除,达到预期阶段的一个快照就叫做一个版本。 如果有一…

【OpenCV入门】第一部分——图像处理基础

本文结构 图像处理的基本操作读取图像imread() 显示图像imshow()waitKey()destroyAllWindows() 保存图像imwrite() 复制图像copy() 获取图像属性 像素确定像素的位置获取像素的BGR值修改像素的BGR值 色彩空间GRAY色彩空间cvtColor()——从BGR色彩空间转换到GRAY色彩空间 HSV色彩…

Lua学习(一)

lua基础学习 LUA 语言1. 什么是lua?1.1 准备工作 2. 基本语法2.1 注释2.2 标识符2.3 关键字2.4 全局变量 3. 数据类型4. 变量4.1 赋值语句 5. 循环5.1 while循环5.2 for循环5.3泛型for循环5.4 repeat until 循环5.5 break 语句 6. 流程控制6.1 if语句6.2 if else 语…

GNU make系列之介绍Makefile(0)

一.欢迎来到我的酒馆 在本章节介绍Makefile。 目录 一.欢迎来到我的酒馆二.GNU make 预览三.一个简单的Makefile四.make程序如何处理Makefile文件五.在Makefile中使用变量 二.GNU make 预览 2.1 GNU make工具会自动决定哪些程序需要被重新编译,并且执行相应的命令来…

leetcode做题笔记96. 不同的二叉搜索树

给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 思路一&#xff1a;动态规划 int numTrees(int n){int f[n1];memset(f,0,sizeof(f));f[0] f[1] 1;for(int i 2;i<n;i)…

reactantd(12)动态表单的默认值问题

最近遇到一个需求是有一个表单可以输入各种信息&#xff0c;然后还需要有一个编辑功能&#xff0c;点击编辑的时候需要把当前数据填入到表单里面。在网上查了很多种方法&#xff0c;然后我的思路是使用initialValues搭配setState()使用。默认值都为空&#xff0c;然后点击单条数…

数学建模:ARMA时间序列预测

&#x1f506; 文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 ARMA预测 时间序列是按时间顺序的一组数字序列 时间序列的特点&#xff1a; 现实的、真实的一组数据&#xff0c;时间序列背后是某一现象的变化规律&#xff0c;时间序列预测就是学习之前的规律来预测后面…

从零开始学习 Java:简单易懂的入门指南之查找算法及排序算法(二十)

查找算法及排序算法 常见的七种查找算法&#xff1a;1. 基本查找2. 二分查找3. 插值查找4. 斐波那契查找5. 分块查找6. 哈希查找7. 树表查找 四种排序算法&#xff1a;1. 冒泡排序1.1 算法步骤1.2 动图演示1.3 代码示例 2. 选择排序2.1 算法步骤2.2 动图演示 3. 插入排序3.1 算…

knife4j 整合 springboot

官方文档&#xff1a;https://doc.xiaominfo.com/knife4j 版本兼容说明&#xff1a;https://doc.xiaominfo.com/docs/quick-start/start-knife4j-version 升级说明&#xff1a;https://doc.xiaominfo.com/docs/upgrading/upgrading-to-v4版本兼容惯关系&#xff1a; springboot…

MySQL一行记录是如何存储的?

目录 MySQL的数据存放在哪个文件&#xff1f; 表空间文件的结构是怎么样的&#xff1f; 1、行&#xff08;row&#xff09; 2、页&#xff08;page&#xff09; 3、区&#xff08;extent&#xff09; 4、段&#xff08;segment&#xff09; InnoDB 行格式有哪些&#xf…

解读亚马逊云科技语义搜图检索方案

图像检索&#xff08;包括文搜图和图搜图&#xff09;是各个行业中常见的一个应用场景。比如在电商场景中&#xff0c;基于以图搜图做相似商品查找&#xff1b;在云相册场景中&#xff0c;基于文搜图来找寻所需的图像素材。 传统基于标签的图像检索方式&#xff0c;即先使用目标…

博流RISC-V芯片Eclipse环境搭建

文章目录 1、下载 Eclipse2、导入 bouffalo_sdk3、编译4、烧录5、使用ninja编译 之前编译是通过 VSCode 编译&#xff0c;通过手工输入 make 命令编译&#xff0c;我们也可以通过 Eclipse 可视化 IDE 来编译、烧录。 1、下载 Eclipse 至 Eclipse 官网 https://www.eclipse.org…