秋招后端开发面试题 - Java多线程(上)


目录

  • Java多线程
    • 前言
    • 面试题
      • 线程和进程?
      • 说说线程有几种创建方式?
      • 为什么调用 start() 方法时会执行 run() 方法,那怎么不直接调用 run() 方法?
      • 线程有哪些常用的调度方法?
      • 线程有几种状态?
      • 守护线程了解吗?
      • 线程间有哪些通信方式?
      • 并发和并行?
      • 同步和异步?
      • 为什么使用多线程?
      • 使用多线程可能带来的问题?
      • 什么是线程上下文切换?
      • 什么是线程死锁?
      • 死锁产生的条件?
      • 如何避免死锁?
      • 那死锁问题怎么排查呢?
      • 活锁和饥饿锁了解吗?
      • 线程间如何同步?
      • sleep() 和 wait()?
      • 为什么 wait() 方法不定义在 Thread 中?
      • 说说你对原子性、可见性、有序性的理解?
      • 如何保证变量的可见性?
      • 那说说什么是指令重排?
      • 指令重排有限制吗?happens-before 了解吗?
      • as-if-serial 又是什么?单线程的程序一定是顺序的吗?
      • volatile 关键字?
      • volatile 实现原理了解吗?
      • 解释双重校验锁实现单例的原理?
      • volatile 可以保证原子性吗?


Java多线程

前言

已经找到工作了,分享秋招时的笔记。祝大家都能顺利找到自己心仪的工作。


面试题

线程和进程?

进程(Process):

  • 进程是操作系统分配资源的基本单位,是程序的一个执行实例
  • 每个进程都有自己独立的内存空间,包括代码、数据、堆栈等
  • 进程之间相互独立,一个进程的崩溃不会影响其他进程
  • 进程间通信需要使用操作系统提供的机制,如管道、消息队列、共享内存等

线程(Thread):

  • 线程是进程的一个执行流,是进程的一部分
  • 线程共享进程的内存空间,因此线程间通信相对更容易
  • 线程可以更轻量级地创建和销毁,开销小

联系与区别:

  • 线程是进程的一部分,一个进程可以包含多个线程
  • 进程是独立的执行环境,拥有独立的内存空间,而线程共享进程的内存空间
  • 进程之间的切换开销较大,涉及上下文切换。线程切换开销相对较小
  • 进程间通信通常需要操作系统提供的机制,而线程间通信相对更容易,可以通过共享内存等方式实现

说说线程有几种创建方式?

  • 继承 Thread 类:重写 run() 方法,调用 start() 方法启动线程
  • 实现 Runnable 接口:重写 run() 方法,调用 start() 方法启动线程
  • 实现 Callable 接口:重写 call() 方法
  • 使用匿名类或 Lambda 表达式
  • 使用线程池

为什么调用 start() 方法时会执行 run() 方法,那怎么不直接调用 run() 方法?

  • 调用 start() 方法会创建一个新线程,然后新线程执行 run() 方法,从而实现多线程并发运行
  • 如果直接调用 run() 方法,就会在当前线程执行,不会启动新线程,就不会实现多线程并发执行

线程有哪些常用的调度方法?

  • wait():使线程进入等待状态
  • join():让线程等待另一个线程执行完成
  • notify()唤醒等待中的一个线程
  • notifyAll()唤醒所有等待中的线程
  • yield():让当前线程让出 CPU 资源
  • interrupt()中断线程
  • isInterrupted()检查线程的中断状态
  • sleep():使线程进入休眠状态

线程有几种状态?

![[image-20230329090159344.png]]

  • 初始状态
  • 运行状态
  • 阻塞状态:需要等待锁释放
  • 等待状态:线程需要等待其他线程做出一些特定动作 (通知或中断)
  • 超时等待状态:可以在指定时间后自行返回
  • 终止状态:线程已经运行完毕

守护线程了解吗?

Java 线程分为两类,分为守护线程用户线程

  • 守护线程服务性质的线程,在所有用户线程结束时会自动结束。通常用来执行后台任务,比如垃圾回收、资源管理等。不影响 JVM 的退出
  • 用户线程:用户手动创建的线程,在程序执行期间一直存在,直到主线程执行完成或者被手动终止。用户线程会影响 JVM 的退出

线程间有哪些通信方式?

  • 共享变量:线程通过读写共享内存中的变量进行通信
  • 锁机制:使用锁来限制对共享资源的访问,从而实现线程的同步和互斥
  • wait-notify 机制:一个线程可以通过 wait 方法进入等待状态,等待其他线程调用 notify/notifyAll 来唤醒
  • 使用管道流:管道流可以在两个线程之间进行数据传输
  • 阻塞队列:一个线程可以通过向队列中添加元素来与其他线程进行通信

并发和并行?

  • 并发:系统能够同时执行多个任务,不一定是同时执行,而是通过任务的切换和调度来实现多个任务交替执行
  • 并行:系统中同时执行多个任务,每个任务在独立的处理器上执行,各个任务之间相互独立

同步和异步?

  • 同步:调用一个函数或方法后,必须等待完成并返回结果,才能继续执行
  • 异步:调用一个函数或方法后,不用等待完成,会通过回调函数、事件触发等机制来处理最终的结果

为什么使用多线程?

  • 提高程序性能:在多核 CPU 上,多线程可以充分利用多核并行处理任务,加快程序的执行速度
  • 提高资源利用率:多线程可以充分利用 CPU 和内存等资源
  • 异步处理:多线程可以实现异步操作,例如在后台加载数据、文件下载等,提高系统的响应性

使用多线程可能带来的问题?

  • 内存泄露
  • 死锁
  • 线程不安全
  • 性能问题

什么是线程上下文切换?

  • 线程上下文切换是指在多线程环境中,由于多个线程共享 CPU 的执行时间
  • 当一个线程的执行时间片用完或者需要切换到另一个线程时,操作系统会暂停当前线程的执行,保存其上下文,然后加载另一个线程的上下文,执行线程

什么是线程死锁?

  • 死锁是多个线程因相互等待对方持有的资源而无法继续执行的僵局状态

死锁产生的条件?

  • 互斥条件:资源只能被一个线程占用
  • 请求并保持条件:已经获得资源的进程请求其他资源,同时不释放已有资源
  • 不剥夺条件:已经占有的资源不能其他的线程抢占
  • 循环等待条件:多个进程之间形成环路,每个进程都在等待下一个进程所占有的资源

如何避免死锁?

  • 破坏死锁的四个必要条件
    • 互斥条件:使用资源分级,避免资源互斥
    • 请求与保持条件:线程在获取资源前释放已持有的资源
    • 不剥夺条件:允许抢占已持有的资源
    • 循环等待条件:强制线程按照一定的顺序获取资源
  • 避免无限期等待
    • 设置资源的超时时间,如果超时未获取,线程放弃或者重试
  • 使用死锁检测和解除机制
    • 定期检测系统中是否存在死锁
  • 使用锁的顺序
    • 确定锁的获取顺序,所有线程按照相同的顺序获取锁

那死锁问题怎么排查呢?

  • 确认是否发生了死锁:查看日志,如果出现线程堵塞的异常情况可能是死锁问题
  • 定位死锁位置:通过分析线程堆栈信息,定位出现死锁的代码位置
  • 确认锁的粒度:确认锁的粒度是否过大,如果锁的粒度过大,容易出现死锁问题
  • 检查锁的维护方式:检查锁是否正常释放
  • 分析并发访问情况:了解多线程请求锁的顺序和时间
  • 制定解决方案:根据以上情况制定解决方案,如调整锁的粒度、优化代码逻辑、增加重试机制
  • 测试验证:在实际系统中测试解决方案是否有效,如果没有解决问题,按照以上步骤继续排查

活锁和饥饿锁了解吗?

  • 活锁:两个或多个线程都在互相等待对方执行某个操作,形成死循环
  • 饥饿锁:某个线程一直无法获取需要的资源

线程间如何同步?

线程间的同步需要通过互斥锁、条件变量和信号量等机制来实现

  • 互斥锁
    • 互斥锁是一种最基本的同步机制,可以实现对共享资源的互斥访问。
    • 当某个线程进入临界区进行访问时,其他线程需要等待,直到该线程离开临界区,释放锁资源,才能再继续访问共享资源
  • 条件变量
    • 条件变量是一种用于线程间等待和通知的机制
    • 当某个线程进入临界区后,如果发现共享资源不满足当前需求,那它就可以将自己休眠,释放锁资源,等待其他线程改变共享资源状态并发送通知以后,再重新唤醒
  • 信号量
    • 信号量是一种更高级的线程同步机制,可以实现多个线程之间的同步操作。
    • 当某个线程需要访问共享资源时,请求获取信号量。如果有其他线程正在使用该共享资源,则该线程进入休眠状态等待信号量被释放。当共享资源被释放时,信号量发出通知,并将等待资源的线程唤醒

sleep() 和 wait()?

在多线程中,sleep() 和 wait() 方法都可以暂停线程的执行

  • sleep() 方法不会释放锁,wait() 会释放锁
  • sleep() 方法通常用于暂停执行,wait() 通常用于线程间通信
  • sleep() 方法在暂停指定时间后,自动恢复运行;wait() 方法调用后,需要其他线程调用 notify/notifyAll 方法唤醒
  • sleep() 方法是 Thread 类方法,wait() 是 Object 类方法

为什么 wait() 方法不定义在 Thread 中?

  • wait() 方法用于线程间通信,通过释放对象的锁并让线程进入等待状态,每个对象都拥有对象锁,因此定义在 Object 类
  • sleep() 方法是让当前线程暂停执行,不涉及对象类,因此定义在 Thread 类中

说说你对原子性、可见性、有序性的理解?

  • 原子性:
    • 原子性指一个操作不可分割的,要么完全执行,要么完全不执行
    • 原子性确保了操作的不可分割性
  • 可见性:
    • 可见性指一个线程对共享数据进行修改后其他线程立即能知道这个修改
    • 可见性确保了线程间共享数据的同步性
  • 有序性:
    • 有序性指程序执行的顺序和代码顺序一致

如何保证变量的可见性?

  • 使用 volatile 关键字:将变量声明为 volatile,每次访问该变量时都会从主存中读取最新的值,而不是使用线程的缓存
  • 使用 synchronized 或 Lock:使用同步机制来确保对变量的访问时互斥的
  • 使用原子类:原子类的操作是原子的,可以保证对变量的修改可见
  • 使用并发集合:使用线程安全的并发集合类,如 ConcurrentHashMap
  • 使用线程间通信:可以使用线程间通信机制,确保线程间的操作顺序和可见性

那说说什么是指令重排?

  • 指令重排是处理器和编译器的一种优化手段
  • 通过优化指令的执行顺序,充分利用处理器的执行单元,减少指令的等待时间,提高程序的执行效率

指令重排有限制吗?happens-before 了解吗?

  • 指令重排有限制,有两个规则 happens-beforeas-if-serial
  • happens-before 规则用来定义多线程间操作的执行顺序
    如果操作 A happens-before 操作 B,那么在程序执行中,A 的效果对 B 可见

as-if-serial 又是什么?单线程的程序一定是顺序的吗?

  • as-if-serial 规则是 Java 内存模型的另一个重要原则
    允许虚拟机在保证多线程正确性的前提下进行指令重排,只要重排后的执行结果和原始执行顺序一致即可
  • 单线程的程序一定是顺序执行的

volatile 关键字?

volatile 关键字可以保证可见性有序性

  • 保证可见性:线程读取变量的值都从主存中读取
  • 保证有序性:volatile 关键字可以禁止指令重排

volatile 实现原理了解吗?

  • volatile 实现可见性和有序性的关键在于内存屏障
  • 内存屏障是一种硬件或软件层面的机制,可以确保在特定位置的操作不会发生在内存屏障之前或之后
  • volatile 变量的读写操作会插入内存屏障,保证读写 volatile 变量时不会指令重排

解释双重校验锁实现单例的原理?

双重校验锁是一种常用于实现线程安全懒汉式单例模式的优化方式

  1. 首次检查:在双重校验锁中,首先检查对象实例是否被创建,如果没有才进行同步
  2. 同步块:在单例对象还没有创建的时候,使用synchronized对代码块加锁,并通过两次检查对象是否被实例化,保证只有一个线程执行了同步块内的代码
  3. volatile 关键字:使用 volatile 关键字确保线程之间的可见性和禁止指令重排序,避免出现另一个线程获得不完全初始化的实例
//双重校验锁实现对象单例(线程安全)
public class Singleton {private volatile static Singleton uniqueInstance;private Singleton() {}public  static Singleton getUniqueInstance() {//先判断对象是否已经实例过,没有实例化过才进入加锁代码if (uniqueInstance == null) {//类对象加锁synchronized (Singleton.class) {if (uniqueInstance == null) {uniqueInstance = new Singleton();}} }return uniqueInstance;}}

volatile 可以保证原子性吗?

  • volatile 关键字不能保证对变量的操作是原子性

秋招后端开发面试题系列目录
一、Java
1.1 Java基础上
1.2 Java基础下
1.3 Java集合
1.4 JavaIO
1.5 Java多线程上
1.6Java多线程下
二、JVM
2.1 JVM底层原理
2.2 垃圾回收器
2.3 垃圾回收算法
2.4 类加载机制
2.5 运行时数据区
三、MySQL
3.1 MySQL基础
3.2 事务
3.3 索引
3.4 锁机制
3.5 MVCC
四、Redis
4.1 Redis基础
4.2 缓存原理
五、中间件
5.1 RabbitMQ
六、Spring开源框架
6.1 Spring
6.2 Spring MVC
6.3 Spring Boot
6.4 MyBatis
七、操作系统
八、计算机网络
九、设计模式
十、微服务架构
十一、Spring Cloud分布式
11.1 分布式基础
11.2 Spring Cloud
11.3 GateWay
11.4 Nacos
11.5 OpenFeign
11.6 Ribbon
十二、算法
十三、项目

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

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

相关文章

深入理解汇编中的ZF、OF、SF标志位和条件跳转

本节课在线学习视频:https://pan.quark.cn/s/bbc4781e5336 汇编语言中的程序控制流常依赖于处理器的状态标志来进行决策。在x86架构中,ZF(Zero Flag)、OF(Overflow Flag)和SF(Sign Flag&#x…

Linux(Centos 7)环境下安装wget,并且更换阿里云镜像

Linux(Centos 7) Minimal 安装后,由于没有预装wget,在使用wget命令去下载安装相关应用时,提示:“wget: command not found” 先在Linux服务器窗口中,输入如下命令,检查Linux服务器有没有安装过wget。 rpm -…

Django信号(Signals)使用案例:自动化工作流程

Django信号(Signals)是一种可以让应用程序组件之间进行解耦的机制。它允许在特定事件发生时发送信号,其他组件可以监听这些信号并做出相应的处理。 在自动化工作流程中,Django信号可以用来触发自动化任务或流程。以下是一个使用D…

deepflow grafana plugin 编译问题解决

修改tsconfig.js 增加"noImplicitAny": false,解决代码类型没有指定,显示Any 错误 To solve the error, explicitly set the parameters type to any, use a more specific type or set noImplicitAny to false in tsconfig.json. https://b…

【大学生电子竞赛题目分析】——2023年H题《信号分离装置》

今年的大赛已临近落幕,笔者打算陆续对几个熟悉领域的题目作一番分析与讨论,今天首先分析H题。 网上有一些关于H题的分析,许多都是针对盲信号分析的。然而本题具有明确的信号频率范围,明确的信号可能频率,明确的信号波…

Jmeter Beanshell 设置全局变量

//获取token import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONArray; import java.util.*; import org.apache.jmeter.util.JMeterUtils; //获取可上机机器 String response prev.getResponseDataAsString(); JSONObject responseObect JSONObjec…

什么是跨域? 出现原因及解决方法

什么是跨域? 出现原因及解决方法 什么是跨域 跨域:浏览器对于javascript的同源策略的限制 。 同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。 设想这样一种情况:A 网站是一家银行,用户登录以后…

K8S哲学 - statefulSet 灰度发布

kubectl get - 获取资源及配置文件 kubectl get resource 【resourceName -oyaml】 kubectl create - 指定镜像创建或者 指定文件创建 kubectl create resource 【resourceName】 --imagemyImage 【-f my.yaml】 kubectl delete kubectl describe resource resourc…

OceanBase 分布式数据库【信创/国产化】- 登录 OceanBase 租户

本心、输入输出、结果 文章目录 OceanBase 分布式数据库【信创/国产化】- 登录 OceanBase 租户前言OceanBase 数据更新架构OceanBase 租户架构登录系统租户通过 MySQL 客户端登录通过 OBClient 登录登录最佳实践登录用户租户登录 Meta 租户OceanBase 分布式数据库【信创/国产化…

UCOSIII章节介绍

UCOSIII章节介绍 一、第一部分(第一章 至 第三十二章)1、整体介绍2、单章介绍第一章 至 第三章:总体概览第四章 至 第五章:准备工作,配置KEIL工程环境第六章:准备工作,KEIL仿真介绍第七章&#…

怎么把试卷答案去掉再打印出来?

在学习中,试卷无疑是检验学习成果的重要工具。然而,当我们想重新练习这些试卷,加深对知识点的理解和记忆时,答案的存在往往会成为他们复习路上的“绊脚石”。那么,有没有一种方法可以轻松去除试卷上的答案,…

亚马逊云科技AWS将推出数据工程师全新认证(有资料)

AWS认证体系最近更新,在原有12张的基础上,将在2023年11月27日添加第13张,数据工程师助理级认证(Data Engineer Associate),并且在2024/1/12前半价(省75刀=544人民币。 原有的数据分析专家级认证(Data Analytics Specia…

Unity功能——开发中逻辑坐标和世界坐标是什么?

声明:本文为个人笔记,用于学习研究使用非商用,内容为个人研究及综合整理所得,若有违规,请联系,违规必改。 Unity功能——逻辑坐标和世界坐标 文章目录 Unity功能——逻辑坐标和世界坐标一.开发环境二.问题描…

qt-C++笔记之滑动条QSlider和QProgressBar进度条

qt-C笔记之滑动条QSlider和QProgressBar进度条 —— 2024-04-28 杭州 本例来自《Qt6 C开发指南》 文章目录 qt-C笔记之滑动条QSlider和QProgressBar进度条1.运行2.阅读笔记3.文件结构4.samp4_06.pro5.main.cpp6.widget.h7.widget.cpp8.widget.ui 1.运行 2.阅读笔记 3.文件结构…

RuoYi-Vue-Plus (SPEL 表达式)

RuoYi-Vue-Plus 中SPEL使用 DataScopeType 枚举类中: /*** 部门数据权限*/DEPT("3", " #{#deptName} #{#user.deptId} ", " 1 0 "), PlusDataPermissionHandler 拦截器中定义了解析器: buildDataFilter 方法中根据注解的…

[LitCTF 2023]Ping、[SWPUCTF 2021 新生赛]error、[NSSCTF 2022 Spring Recruit]babyphp

[LitCTF 2023]Ping 尝试ping一下127.0.0.1成功了,但要查看根目录时提示只能输入IP 查看源代码,这段JavaScript代码定义了一个名为check_ip的函数,用于验证输入是否为有效的IPv4地址。并且使用正则表达式re来匹配IPv4地址的格式。 对于这种写…

机器学习:基于Sklearn、XGBoost框架,使用逻辑回归、支持向量机和XGBClassifier预测帕金森病

前言 系列专栏:机器学习:高级应用与实践【项目实战100】【2024】✨︎ 在本专栏中不仅包含一些适合初学者的最新机器学习项目,每个项目都处理一组不同的问题,包括监督和无监督学习、分类、回归和聚类,而且涉及创建深度学…

【已解决】Python Selenium chromedriver Pycharm闪退的问题

概要 根据不同的业务场景需求,有时我们难免会使用程序来打开浏览器进行访问。本文在pycharm中使用selenium打开chromedriver出现闪退问题,根据不断尝试,最终找到的问题根本是版本问题。 代码如下 # (1) 导入selenium from selenium import …

科研学习|论文解读——CVPR 2021 人脸造假检测(论文合集)

随着图像合成技术的成熟,利用一张人脸照片合成假视频/不良视频现象越来越多,严重侵犯个人隐私、妨碍司法公正,所以人脸造假检测越来越重要,学术界的论文也越来越多。 一、研究1 1.1 论文题目 Multi-attentional Deepfake Detecti…

自学Python爬虫js逆向(二)chrome浏览器开发者工具的使用

js逆向中很多工作需要使用浏览器中的开发者工具,所以这里以chrome为例,先把开发者工具的使用总结一下,后面用到的时候可以回来查询。 Google Chrome浏览器的开发者工具是前端开发者的利器,它不仅提供了丰富的功能用于开发、调试和…