【Java】线程相关面试题 (基础)

news2024/12/31 23:29:02

文章目录

  • 线程与进程区别
  • 并行与并发区别解析
      • 概念含义
      • 资源利用
      • 执行方式
      • 应用场景
  • 创建线程
  • 线程状态
  • 如何保证新建的三个线程按顺序执行
  • wait方法和sleep方法的不同
      • 所属类和使用场景
      • 方法签名和参数说明
      • 调用`wait`方法的前提条件
      • 被唤醒的方式
      • 与`notify`/`notifyAll`方法的协作
      • 使用示例
      • 注意事项
  • 停止线程的三种方式

线程与进程区别

在这里插入图片描述

  • 进程的定义与实例
    • 进程是当程序被运行,从磁盘加载程序代码到内存时开启的。例如打开谷歌浏览器或txt文档等程序就是开启了一个进程,在Windows中有多实例进程(可打开多份,如浏览器、txt文档)和单实例进程(如tears客户端、企业微信在系统层面只能打开一份)。
  • 线程的定义与作用
    • 线程包含指令,交给CPU运行。进程至少包含一到多个线程,每个线程执行不同任务。
  • 线程与进程的区别
    • 进程是正在运行的程序实例,包含多个线程执行不同任务。不同进程使用不同内存空间,而当前进程下的所有线程可以共享该进程的内存空间。线程更轻量,其上下文切换成本一般比进程上下文切换成本低。面试时主要回答这三点:进程和线程的关系、内存占用情况(强调进程下线程共享内存)、线程更轻量且切换成本低。

并行与并发区别解析

概念含义

  • 并行:同一时间动手做多件事情的能力。例如在多核CPU下,多个核心可以同时执行不同的线程,像四核CPU能同时执行四个线程,这些线程是真正意义上的同时进行
  • 并发:同一时间应对多件事情的能力。在单核CPU中,由于只有一个核心,多个线程不能同时执行,而是通过任务管理器分配时间片,轮流使用CPU,虽然每个时间片只有一个线程执行,但因CPU切换速度快,宏观上给人一种并行的感觉,微观上实际是串行执行。例如家庭主妇独自做饭、打扫卫生、给孩子喂奶,一个人轮流交替做这些事,就如同单核CPU处理多线程任务。

资源利用

  • 并行:需要多核CPU等硬件资源支持,每个核心可以独立运行一个线程,实现真正的同时处理多个任务,充分利用了多核CPU的计算能力,提高了整体任务处理效率。
  • 并发:主要依赖于操作系统的调度机制,在单核CPU环境下,通过合理分配时间片给不同线程,让多个任务看起来像是同时在处理,有效利用了单个CPU的时间资源,避免某个线程长时间占用CPU导致其他线程等待过久,但整体效率受限于单核CPU的处理能力。

执行方式

  • 并行:多个任务在多个处理器或多核CPU的不同核心上同时执行,任务之间相互独立,不存在资源竞争(除非访问共享资源时需要进行同步处理),执行顺序是真正意义上的同时进行。
  • 并发:多个任务在单核CPU上通过时间片轮转的方式交替执行,每个任务执行一段时间后暂停,切换到下一个任务,由于时间片很短,给用户造成任务在同时进行的错觉,但实际上在微观层面是串行执行的,任务之间可能存在频繁的上下文切换开销。

应用场景

  • 并行:适用于计算密集型任务,如大规模数据处理、复杂科学计算等,通过将任务分解到多个核心上同时计算,可以显著缩短计算时间,提高计算性能。例如在图像渲染、视频编码解码等领域,利用多核CPU并行处理不同部分的图像或视频数据,能快速完成处理工作。
  • 并发:常用于I/O密集型任务,如网络通信、文件读写等操作,这些任务在等待I/O操作完成时会阻塞线程,使用并发可以在等待一个任务的I/O操作时切换到其他任务执行,提高CPU利用率,避免线程长时间空闲等待。比如在一个Web服务器中,同时处理多个客户端的请求,每个请求在等待数据库查询或文件读取等I/O操作时,服务器可以切换去处理其他客户端请求,提高整体响应能力。

创建线程

  1. 创建线程的方式介绍

    • 创建线程共有四种方式,分别是继承Thread类、实现Runnable接口、实现Callable接口和使用线程池创建线程。
  2. 继承Thread类创建线程

    • 定义一个类继承Thread类,重写run方法,在run方法中编写线程要执行的代码。
    • 使用时先创建该类的对象,然后调用start方法开启线程,new两次对象相当于开两个线程。
  3. 实现Runnable接口创建线程

    • 定义一个类实现Runnable接口,重写run方法,该方法为线程执行的代码。
    • 使用时先创建类的对象,将其包装在Thread类中,再调用Thread对象的start方法开启线程,new两次对象相当于开两个线程。
  4. 实现Callable接口创建线程

    • 定义一个类实现Callable接口,重写call方法,call方法有返回值(通过泛型指定)且可抛异常,call方法的代码为线程要执行的逻辑。
    • 使用时先创建类的对象,配合FutureTask包装该对象,再将FutureTask包装在Thread类中,调用Thread对象的start方法开启线程,通过FutureTask的get方法获取线程执行后的返回值。
  5. 使用线程池创建线程

    • 创建一个类实现Runnable或Callable接口,编写线程执行逻辑。
    • 使用时先创建固定大小的线程池(线程池后期会详细讲解),通过线程池的submit方法提交任务(即实现接口的类的对象),线程池会自动执行线程中的逻辑。
  6. Runnable和Callable的区别

    • 返回值:Runnable接口的run方法无返回值,Callable接口的call方法有返回值且需配合FutureTask使用get方法获取返回值。
    • 异常处理:run方法不能抛异常,只能内部try - catch处理;call方法可以抛异常。
  7. start方法和run方法的区别

    • 功能:start方法用于启动线程,线程独立执行run方法中的代码;run方法是普通方法,直接调用如同调用普通方法,在当前线程顺序执行代码。
    • 调用次数:start方法只能被调用一次启动线程,多次调用会抛异常;run方法可多次调用。
  8. 总结

    • 创建线程有继承Thread类、实现Runnable接口、实现Callable接口和使用线程池四种方式,项目中一般使用线程池创建线程。
    • Runnable和Callable的区别主要在返回值、异常处理方面。
    • start方法用于启动线程且只能调用一次,run方法是普通方法可多次调用。

线程状态

  1. 线程状态面试题介绍
    • 状态定义:参考Thread类的内部枚举类State,定义了六个线程状态,即new(新建)、runnable(可运行)、block(阻塞)、waiting(等待)、time waiting(时间等待)、terminated(终结)。

在这里插入图片描述

  1. 线程状态及转换初步讲解
    • 新建状态:创建线程对象时进入,如创建线程t1和t2时。
    • 就绪与运行状态:调用线程方法后进入就绪状态,抢到CPU时间片才有执行权,线程运行完成后进入死亡状态。
    • 阻塞状态:线程加锁时,未获得锁的线程进入阻塞状态,获得到锁后转为可运行状态。
    • 等待状态:线程内部调用wait方法进入等待状态,其他线程调用notify或notifyAll方法唤醒后变为可运行状态。
    • 时间等待状态:线程调用sleep方法进入时间等待状态,时间结束后转为可运行状态。
  2. 总结线程状态及转换
    • 线程状态总结:包含六个状态,新建、可运行、阻塞、等待、计时等待、终止状态。
    • 状态转换关系梳理
      • 新建到可执行:创建线程对象为新建状态,调用方法后转换为可执行状态。
      • 可执行到终止:线程获取CPU执行权并执行结束后为终止状态。
      • 可执行状态的其他转换
        • 可执行到阻塞:未获取到锁(如synchronized或Lock锁)进入阻塞状态,获得到锁的执行权后切换为可执行状态。
        • 可执行到等待:调用wait方法进入等待状态,其他线程调用notify或notifyAll唤醒后切换为可执行状态。
        • 可执行到计时等待:调用sleep方法进入计时等待状态,时间到后切换为可执行状态。

文章目录

  • 线程与进程区别
  • 并行与并发区别解析
      • 概念含义
      • 资源利用
      • 执行方式
      • 应用场景
  • 创建线程
  • 线程状态
  • 如何保证新建的三个线程按顺序执行
  • wait方法和sleep方法的不同
      • 所属类和使用场景
      • 方法签名和参数说明
      • 调用`wait`方法的前提条件
      • 被唤醒的方式
      • 与`notify`/`notifyAll`方法的协作
      • 使用示例
      • 注意事项
  • 停止线程的三种方式


如何保证新建的三个线程按顺序执行

  • 方法介绍
    • 对于“如何保证新建t1、t2、t3三个线程按顺序执行”这一面试题,可使用线程中的“join方法”来解决。该方法的作用是等待线程运行结束,调用此方法的线程会被阻塞,进入time waiting(时间等待)状态,直到被调用“join方法”的线程执行完成后,调用者才能继续执行。
  • 代码演示
  • 在代码中创建了t1、t2、t3三个线程,在t2线程中调用了t1的“join方法”,这意味着t2线程想要运行必须等待t1线程结束;在t3线程中调用了t2的“join方法”,所以t3线程需等待t2线程运行结束后才能运行。启动线程的顺序不影响最终结果,最终会按t1、t2、t3的顺序执行。通过代码执行结果展示了t1先执行,完成后t2执行,t2执行完t3执行,从而验证了这种方法可保证线程按顺序执行。
  1. notify和notifyAll的区别

    为notify是只随机唤醒一个等待(wait)方法的线程,而notifyAll是唤醒所有等待方法的线程。


wait方法和sleep方法的不同

在这里插入图片描述

在Java中,wait方法用于使当前线程等待,直到其他线程调用该对象的notify方法或notifyAll方法唤醒它,或者等待一定的时间(如果指定了超时时间)。以下是关于wait方法的详细介绍:

所属类和使用场景

  1. 所属类wait方法属于Object类,这意味着Java中的任何对象都可以调用该方法。
  2. 使用场景:主要用于多线程编程中,实现线程之间的协作和同步。例如,当一个线程需要等待某个条件满足时,可以调用wait方法进入等待状态,直到其他线程改变了共享资源的状态并通知它。

方法签名和参数说明

  1. 方法签名public final void wait() throws InterruptedExceptionpublic final native void wait(long timeout) throws InterruptedException
  2. 参数说明
    • 无参的wait方法会使当前线程无限期等待,直到被唤醒。
    • 带参数的wait方法接受一个long类型的参数,表示等待的超时时间(以毫秒为单位)。如果在指定时间内没有被唤醒,线程会自动苏醒并继续执行。

调用wait方法的前提条件

  1. 当前线程必须拥有该对象的锁。也就是说,wait方法必须在同步代码块(synchronized块)中调用,否则会抛出IllegalMonitorStateException异常。
  2. 例如,以下代码演示了正确调用wait方法的方式:
synchronized (object) {
    // 当前线程获取了object对象的锁,可以调用wait方法
    object.wait();
}

被唤醒的方式

  1. 其他线程调用notify方法:唤醒在此对象监视器上等待的单个线程。如果有多个线程在等待,选择是任意的,由操作系统的调度策略决定。
  2. 其他线程调用notifyAll方法:唤醒在此对象监视器上等待的所有线程。被唤醒的线程将竞争重新获取对象的锁,然后继续执行。
  3. 等待超时:如果调用了带超时参数的wait方法,当超时时间到达时,线程会自动苏醒,继续执行后续代码。

notify/notifyAll方法的协作

  1. wait方法与notify/notifyAll方法必须在同一对象上调用,以实现线程之间的正确协作。
  2. 通常,一个线程在等待某个条件时调用wait方法,而另一个线程在改变条件后调用notifynotifyAll方法来唤醒等待的线程。

使用示例

以下是一个简单的示例,展示了wait方法和notify方法的基本用法:

public class WaitNotifyExample {
    public static void main(String[] args) {
        final Object lock = new Object();

        // 线程1:等待条件满足
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("线程1:开始等待");
                    lock.wait(); // 释放锁并等待
                    System.out.println("线程1:被唤醒,继续执行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        // 线程2:改变条件并通知线程1
        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("线程2:改变条件,并通知线程1");
                lock.notify(); // 唤醒等待的线程1
            }
        });

        thread1.start();
        try {
            Thread.sleep(1000); // 确保线程1先进入等待状态
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread2.start();
    }
}

在上述示例中,线程1获取lock对象的锁后调用wait方法进入等待状态,同时释放锁。线程2获取lock对象的锁后调用notify方法唤醒线程1,线程1被唤醒后重新竞争锁,获取锁后继续执行后续代码。

注意事项

  1. 在使用wait方法时,必须在循环中调用,以避免虚假唤醒(spurious wakeup)的问题。虚假唤醒是指线程在没有被其他线程明确唤醒的情况下苏醒,可能是由于操作系统或JVM的内部原因。例如:
while (condition) {
    synchronized (object) {
        object.wait();
    }
}
  1. 调用wait方法的线程会释放对象的锁,但在被唤醒后重新竞争锁。如果多个线程同时竞争锁,唤醒顺序是不确定的,取决于操作系统的调度策略。
  2. wait方法会抛出InterruptedException异常,当线程在等待过程中被中断时,会抛出该异常。因此,在调用wait方法时,需要正确处理异常,以确保程序的稳定性和正确性。

在这里插入图片描述


文章目录

  • 线程与进程区别
  • 并行与并发区别解析
      • 概念含义
      • 资源利用
      • 执行方式
      • 应用场景
  • 创建线程
  • 线程状态
  • 如何保证新建的三个线程按顺序执行
  • wait方法和sleep方法的不同
      • 所属类和使用场景
      • 方法签名和参数说明
      • 调用`wait`方法的前提条件
      • 被唤醒的方式
      • 与`notify`/`notifyAll`方法的协作
      • 使用示例
      • 注意事项
  • 停止线程的三种方式


停止线程的三种方式

  1. 停止线程的三种方式
    • 使用退出标志:通过定义一个标志变量(如flag),在run方法中使用循环条件控制线程执行,当标志变量改变时,线程正常退出。例如,在my interrupt 1类中,run方法里使用while循环(while (!flag)),线程在循环内打印信息并睡眠3秒。主线程启动该线程后睡眠6秒,然后将flag改为true,使线程在6秒后正常退出。
    • 调用stop方法(不推荐)stop方法可以强行终止线程,但此方法已作废不推荐使用。
    • 调用interrupt方法:该方法包含两种情况。
      • 一是打断阻塞的线程(如处于sleepwaitjoin状态的线程),调用interrupt会抛出InterruptException异常;
      • 二是打断正常的线程,可根据线程的打断状态标记是否退出线程,与第一种使用退出标志的方式类似。
      • 在这里插入图片描述

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

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

相关文章

手机租赁平台开发全攻略打造高效便捷的租赁服务系统

内容概要 手机租赁平台开发,简单说就是让用户能轻松租赁各类手机的高效系统。这一平台不仅帮助那些想要临时使用高端手机的人们节省了不少资金,还为商家开辟了新的收入渠道。随着智能手机的普及,很多人并不需要长期拥有一部手机,…

【视觉惯性SLAM:十一、ORB-SLAM2:跟踪线程】

跟踪线程是ORB-SLAM2的核心之一,其主要任务是实时跟踪相机的位姿变化和场景的变化,以维持地图的更新和相机轨迹的估计。ORB-SLAM2的跟踪线程通过多种方式(参考关键帧跟踪、恒速模型跟踪、重定位跟踪、局部地图跟踪)处理跟踪丢失、…

浙江肿瘤医院病理库存储及NAS共享存储(磁盘阵列)方案-Infortrend普安科技

Infortrend金牌代理-燊通智联信息科技发展(上海)有限公司与院方多轮沟通,详细讨论性能与容量要求,最终决定采用GSe统一存储设备,与现有病理系统服务器无缝对接,每台设备配1.92T SSD作缓存加速原数据读写&am…

解决GPT公式复制到Word之后乱码问题

chat辅助确实很有用。不论是出文稿还是代码。如何把chatgpt中的公式直接复制到word中且保持原样格式呢?下面的方法经过我的验证确实好用,成功解决了最近的论文报告写公式的问题。 一、首先复制chatgpt里面的公式 二、粘贴在下面网站 网站:Mat…

Spring Boot教程之四十:使用 Jasypt 加密 Spring Boot 项目中的密码

如何使用 Jasypt 加密 Spring Boot 项目中的密码 在本文中,我们将学习如何加密 Spring Boot 应用程序配置文件(如 application.properties 或 application.yml)中的数据。在这些文件中,我们可以加密用户名、密码等。 您经常会遇到…

Quartz任务调度框架实现任务动态执行

说明:之前使用Quartz,都是写好Job,指定一个时间点,到点执行。最近有个需求,需要根据前端用户设置的时间点去执行,也就是说任务执行的时间点是动态变化的。本文介绍如何用Quartz任务调度框架实现任务动态执行…

Scala_【1】概述

第一章 语言特点环境搭建(Windows)idea编写scalaHelloWorld注意事项 Scala是一门以Java虚拟机(JVM)为运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言 语言特点 Scala是一门多范式的编程语言,Scala支持面向对象和函…

StableAnimator模型的部署:复旦微软提出可实现高质量和高保真的ID一致性人类视频生成

文章目录 一、项目介绍二、项目部署模型的权重下载提取目标图像的关节点图像(这个可以先不看先用官方提供的数据集进行生成)提取人脸(这个也可以先不看)进行图片的生成 三、模型部署报错 一、项目介绍 由复旦、微软、虎牙、CMU的…

最新高性能多目标优化算法:多目标麋鹿优化算法(MOEHO)求解LRMOP1-LRMOP6及工程应用---盘式制动器设计,提供完整MATLAB代码

一、麋鹿优化算法 麋鹿优化算法(Elephant Herding Optimization,EHO)是2024年提出的一种启发式优化算法,该算法的灵感来源于麋鹿群的繁殖过程,包括发情期和产犊期。在发情期,麋鹿群根据公麋鹿之间的争斗分…

螺杆支撑座在运用中会出现哪些问题?

螺杆支撑座是一种用于支撑滚珠螺杆的零件,通常用于机床、数控机床、自动化生产线等高精度机械设备中。在运用中可能会出现多种问题,这些问题源于多个方面,以下是对可能出现的问题简单了解下: 1、安装不当:安装过程中没…

Unity3d UGUI如何优雅的实现Web框架(Vue/Rect)类似数据绑定功能(含源码)

前言 Unity3d的UGUI系统与Web前端开发中常见的数据绑定和属性绑定机制有所不同。UGUI是一个相对简单和基础的UI系统,并不内置像Web前端(例如 Vue.js或React中)那样的双向数据绑定或自动更新UI的机制。UGUI是一种比较传统的 UI 系统&#xff…

从0入门自主空中机器人-2-2【无人机硬件选型-PX4篇】

1. 常用资料以及官方网站 无人机飞控PX4用户使用手册(无人机基本设置、地面站使用教程、软硬件搭建等):https://docs.px4.io/main/en/ PX4固件开源地址:https://github.com/PX4/PX4-Autopilot 飞控硬件、数传模块、GPS、分电板等…

Windows上缺少xaudio2_9.dll是什么原因?

一、文件丢失问题:Windows上缺少xaudio2_9.dll是什么原因? xaudio2_9.dll是DirectX音频处理库的一个组件,它支持游戏中的音频处理功能。当你在Windows系统上运行某些游戏或音频软件时,如果系统提示缺少xaudio2_9.dll文件&#xf…

冥想的实践

这是我某一天的正念和冥想实践,我对正念练习、冥想练习进行了分别的统计。 正念练习:1分钟**5次 冥想:15分钟10分钟 正念练习,基本在工作休息时间练习。当然,工作过程中,也有一部分时间会有正念的状态&am…

一个简单的机器学习实战例程,使用Scikit-Learn库来完成一个常见的分类任务——**鸢尾花数据集(Iris Dataset)**的分类

机器学习实战通常是将理论与实践结合,通过实际的项目或案例,帮助你理解并应用各种机器学习算法。下面是一个简单的机器学习实战例程,使用Scikit-Learn库来完成一个常见的分类任务——**鸢尾花数据集(Iris Dataset)**的…

Redis 实战篇 ——《黑马点评》(上)

《引言》 在进行了前面关于 Redis 基础篇及其客户端的学习之后,开始着手进行实战篇的学习。因内容很多,所以将会分为【 上 中 下 】三篇记录学习的内容与在学习的过程中解决问题的方法。Redis 实战篇的内容我写的很详细,为了能写的更好也付出…

Intent--组件通信

组件通信1 获取子活动的返回值 创建Activity时实现自动注册!【Activity必须要注册才能使用】 默认 LinearLayout 布局,注意 xml 中约束布局的使用; 若需要更改 线性布局 只需要将标签更改为 LinearLayout 即可,记得 设置线性布局…

word参考文献第二行缩进对齐

刚添加完参考文献的格式是这样: ”段落“—>缩进修改、取消孤行控制 就可以变成

UE(虚幻)学习(一) UE5.3.2和VS2022的安装以及遇到的问题和一些CS8604、CA2017报错问题.

最近工作很多东西是UE搞的,工作安排上也稍微缓口气,来学学UE,因为同事都用的UE5.3,所以就从UE5.3开始吧,之前学习过UE4,放上两年什么都不记得了。还是需要做一些记录。 本来安装不想写什么,谁知…

【YOLOv3】源码(train.py)

概述 主要模块分析 参数解析与初始化 功能:解析命令行参数,设置训练配置项目经理制定详细的施工计划和资源分配日志记录与监控 功能:初始化日志记录器,配置监控系统项目经理使用监控和记录工具,实时跟踪施工进度和质量…