【java面试】线程篇

  • 一、基础知识
    • 1 线程与进程的区别
    • 2 并行与并发的区别
    • 3 创建线程的方式
    • 4 线程包含了哪些状态,状态之间是如何变化的?
    • 5 新建三个线程,如何保证他们按照顺序执行?
    • 6、java中的wait和sleep方法的不同
    • 7 如何停止一个正在运行的线程
  • 二、线程并发安全
    • 1 synchronized关键字的底层原理
      • 1.1 synchronized关键字的使用
      • 1.2 Monitor
      • 1.3 总结
    • 2 synchronized关键字的底层原理--进阶
      • 1.1 Monitor重量级锁
      • 1.2 轻量级锁
      • 1.3 偏向锁
      • 1.4 总结
    • 3 JMM(java memory Model--Java内存模型)
    • 4 CAS
      • 4.1 基本概念
      • 4.2 底层实现
      • 4.3 乐观锁和悲观锁
      • 4.4 总结
    • 4 volatile
      • 4.1 保证线程间的可见性
      • 4.2 volatile禁止指令重排序
      • 4.3 总结
    • 5 AQS
      • 5.1 基本概念
      • 5.2 基本工作机制
      • 5.3 总结
    • 5 ReentrantLock实现原理
    • 7 synchronized与Lock有什么区别?
    • 8 死锁产生的条件
      • 8.1 基本概念
      • 8.2 死锁诊断
    • 9 ConcurrentHashMap
    • 10 导致并发程序出现问题的根本原因
  • 三、线程池
    • 1 线程池的核心参数
      • 1.1 核心参数
      • 1.2 执行原理
    • 2 线程池中常见阻塞队列
    • 3 如何确定核心线程数
    • 4 线程池种类
    • 5 为什么不建议Executor创建线程池
  • 四、使用场景
    • 1 线程池使用场景
    • 2 es数据批量导入
    • 3 数据汇总
    • 4 异步调用
    • 5 如何控制某个方法允许并发访问的数量
    • 6 谈谈对TreadLocal的理解
      • 6.1 set方法
      • 6.2 get方法/remove方法
      • 6.3 ThreadLoca内存泄漏问题

在这里插入图片描述

一、基础知识

1 线程与进程的区别

①进程
程序由指令数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理IO的
当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程
在这里插入图片描述

②线程
一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给CPU 执行,一个进程之内可以分为一到多个线程。
在这里插入图片描述
③二者区别

  • 进程是正在运行程序的实例,进程中包含了线程,每个线程执行不同的任务
  • 不同的进程使用不同的内存空间,在当前进程下的所有线程可以共享内存空间
  • 线程更轻量,线程上下文切换成本一般上要比进程上下文切换低(上下文切换指的是从一个线程切换到另一个线程)

2 并行与并发的区别

在这里插入图片描述
在这里插入图片描述

  • 并发(concurrent)是同一时间应对(dealing with)多件事情的能力
  • 并行(parallel)是同一时间动手做(doing)多件事情的能力

在这里插入图片描述

3 创建线程的方式

①继承Thread类
在这里插入图片描述

②实现runable接口
在这里插入图片描述

③实现Callable接口(适用于有返回值的)
在这里插入图片描述

④线程池创建线程
在这里插入图片描述

开启线程的方法?

  • 继承Thread类
  • 实现runnable接口
  • 实现Callable接口
  • 线程池创建线程(项目中使用方式)

使用tunable和callable都可以创建线程,它们之间有什么区别?

  • Runnable接口run方法没有返回值
  • Callable接口call方法有返回值,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果
  • Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛

在启动线程时可以使用run方法吗?run()和start()有什么区别?

  • start():用来启动线程,通过该线程调用run方法执行run方法中所定义的逻辑代码。start方法只能被调用一次。(线程只能被开启一次)
  • run():封装了要被线程执行的代码,可以被调用多次。

4 线程包含了哪些状态,状态之间是如何变化的?

线程之间包含了那些状态?
新建(NEW) 、可运行(RUNNABLE)、阻塞(BLOCKED)、等待( WAITING )、时间等待(TIMED_WALTING)、终止(TERMINATED)

在这里插入图片描述

状态之间如何转换?

在这里插入图片描述

在这里插入图片描述

5 新建三个线程,如何保证他们按照顺序执行?

join{}:等待线程结束

例如:t.join(),阻塞调用次方的的线程进入time_waiting,直到线程t完成后,此线程在继续执行。

在这里插入图片描述

notify()和notifyAll()有什么区别?

  • notifyAll():唤醒所有wait的线程
  • notify():只随机唤醒一个wait线程

6、java中的wait和sleep方法的不同

在这里插入图片描述

7 如何停止一个正在运行的线程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、线程并发安全

1 synchronized关键字的底层原理

1.1 synchronized关键字的使用

Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】,其它线程再想获取这个【对象锁】时就会阻塞住

在这里插入图片描述

未加锁:出现超卖的情况
在这里插入图片描述
加锁后:一个线程在扣票的过程中,另一个线程是无法去获取的
在这里插入图片描述

1.2 Monitor

在这里插入图片描述

在这里插入图片描述

  • Owner:存储当前获取锁的线程的,只能有一个线程可以获取
  • EntryList:关联没有抢到锁的线程,处于Blocked状态的线程
  • WaitSet:关联调用了wait方法的线程,处于Waiting状态的线程

1.3 总结

  • Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】
  • 它的底层由monitor实现的,monitor是jvm级别的对象(C++实现),线程获得锁需要使用对象(锁)关联monitor
  • 在monitor内部有三个属性,分别是owner、entrylist、waitset
  • 其中owner是关联的获得锁的线程,并且只能关联一个线程;entrylist关联的是处于阻塞状态的线程; waitset关联的是处于Waiting状态的线程

2 synchronized关键字的底层原理–进阶

Monitor实现的锁属于重量级锁,你了解过锁升级码?

  • Monitor实现的锁属于重量级锁,里面涉及到了用户态和内核态的切换、进程的上下文切换,成本较高,性能比较低.
  • 在JDK 1.6引入了两种新型锁机制:偏向锁和轻量级锁,它们的引入是为了解决在没有多线程竞争或基本没有竞争的场景下因使用传统锁机制带来的性能开销问题。

1.1 Monitor重量级锁

lock对象锁是怎么关联上Monitor的?
每个Java对象都可以关联一个Monitor对象,如果使用synchronized给对象上锁(重量级)之后,该对象头的Mark Word 中就被设置指向Monitor对象的指针

通过java对象的内存结构来说明:

MarkWord
在这里插入图片描述

1.2 轻量级锁

在很多的情况下,在Java程序运行时,同步块中的代码都是不存在竞争的,不同的线程交替的执行同步块中的代码。这种情况下,用重量级锁是没必要的。因此JVM引入了轻量级锁的概念。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

1.3 偏向锁

轻量级锁在没有竞争时(就自己这个线程),每次重入仍然需要执行CAS操作。Java 6中引入了偏向锁来做进一步优化:只有第一次使用CAS将线程ID设置到对象的Mark Word头,之后发现这个线程ID是自己的就表示没有竞争,不用重新CAS。以以后只要不发生竞争,这个对象就归该线程所有
在这里插入图片描述

1.4 总结

Java中的synchronized有偏向锁、轻量级锁、重量级锁三种形式,分别对应了锁只被一个线程持有、不同线程交替持有锁、多线程竞争锁三种情况。
在这里插入图片描述
一旦锁发生了竞争都会升级为重量级锁

3 JMM(java memory Model–Java内存模型)

JMM(Java Memory Model)Java内存模型,定义了共享内多线程程序读写操作的行为规范,通过这些规则来规范对内存的读写操作从而保证指令的正确性

在这里插入图片描述

  • JMM(Java Memory Model)Java内存模型,定义了共享内存中多线程程序读写操作的行为规范,通过这些规则来规范对内存的读写操作从而保证指令的正确性
  • JMM把内存分为两块,一块是私有线程的工作区域(工作内存),一块是所有线程的共享区域(主内存)
  • 线程跟线程之间是相互隔离,线程跟线程交互需要通过主内存

4 CAS

4.1 基本概念

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
比对失败,重新读一份V到线程B的A中,设置阈值,多少次之后还没修改成功,就放弃修改。

4.2 底层实现

CAS 底层依赖于一个Unsafe类来直接调用操作系统底层的cAs指令
native修饰的本地方法,是系统提供的,不是java提供的,是由C或者C++实现的。
在这里插入图片描述

在这里插入图片描述

4.3 乐观锁和悲观锁

CAS是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算改了也没关系,我吃亏点再重试呗。
synchronized是基于悲观锁的思想:最悲观的估计,得防着其它线程来修改共享变量,我上了锁你们都别想改,我改完了解开锁,你们才有机会。

4.4 总结

在这里插入图片描述

4 volatile

请谈谈对volatile的理解?
volatile是一个关键字,一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
①保证线程间的可见性
②禁止进行指令重排序

4.1 保证线程间的可见性

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

4.2 volatile禁止指令重排序

在这里插入图片描述
测试:
a.引入依赖
在这里插入图片描述
b.加注解
在这里插入图片描述
c.没有main方法无法执行,自己指定
在这里插入图片描述

在这里插入图片描述

d.查看执行结果
在这里插入图片描述

在这里插入图片描述
y上加volatile关键字运行结果:在X上不行。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.3 总结

在这里插入图片描述

5 AQS

5.1 基本概念

在这里插入图片描述

5.2 基本工作机制

在这里插入图片描述

多个线程争抢资源如何保证原子性?

在这里插入图片描述
在这里插入图片描述

AQS是公平锁还是非公平锁?
既可以实现公平锁也可以实现非公平锁。

线程1释放锁之后,新来的线程5和等待队列的队首线程竞争锁
在这里插入图片描述
新的线程与队列中的线程共同来抢资源,是非公平锁
新的线程到队列中等待,只让队列中的head线程获取锁,是公平锁

5.3 总结

在这里插入图片描述

5 ReentrantLock实现原理

ReentrantLock翻译过来是可重入锁,相对于synchronized它具备以下特点:

  • 可中断:
  • 可以设置超时时间:超过时间没有获取到锁可以放弃获取锁
  • 可以设置公平锁
  • 支持多个条件变量:可以设置多个条件让线程进入等待状态
  • 与synchronized一样,都支持重入


在这里插入图片描述
在这里插入图片描述
总结:
在这里插入图片描述

7 synchronized与Lock有什么区别?

在这里插入图片描述

8 死锁产生的条件

8.1 基本概念

在这里插入图片描述

8.2 死锁诊断

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

9 ConcurrentHashMap

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

10 导致并发程序出现问题的根本原因

导致并发程序出现问题的根本原因
(或者说:java程序中怎么保证多线程的执行安全)

java并发编程的三大特性:

  • 原子性
  • 可见性
  • 有序性

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、线程池

1 线程池的核心参数

说一下线程池的核心参数
(线程池的执行原理知道吗)

1.1 核心参数

在这里插入图片描述

1.2 执行原理

在这里插入图片描述

2 线程池中常见阻塞队列

在这里插入图片描述
在这里插入图片描述

3 如何确定核心线程数

在这里插入图片描述
在这里插入图片描述

4 线程池种类

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5 为什么不建议Executor创建线程池

在这里插入图片描述

四、使用场景

1 线程池使用场景

线程池使用场景(CountDownLatch、future)
你做过的项目中哪里用到了多线程

在这里插入图片描述

2 es数据批量导入

在这里插入图片描述

在这里插入图片描述

3 数据汇总

在这里插入图片描述
在这里插入图片描述

4 异步调用

保存搜索记录,不能影响当前搜索的搜索结果。
在这里插入图片描述
在这里插入图片描述

5 如何控制某个方法允许并发访问的数量

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6 谈谈对TreadLocal的理解

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.1 set方法

在这里插入图片描述

6.2 get方法/remove方法

在这里插入图片描述

6.3 ThreadLoca内存泄漏问题

java对象中四种引用类型:强引用、软引用、弱引用、虚引用
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

RAGFlow是一个基于深度文档理解的开源RAG引擎

RAGFlow概述 RAGFlow是一款基于深度文档理解的开源RAG(检索增强生成)引擎,专注于处理复杂文档结构并提供精准的语义检索与生成能力。其核心优势在于结合多模态文档解析和智能分段技术,优化传统RAG流程中的信息提取与答案生成效果…

Git Commit 模板完整配置指南

Git Commit 模板完整配置指南 📋 目录 Git Commit 模板完整配置指南 📋 目录🎯 为什么需要 Commit 模板📝 推荐的 Commit 模板 标准模板格式C 项目特化模板 ⚙️ 系统级配置 1. 创建模板文件2. 配置 Git 使用模板3. 验证配置 &a…

【ELK服务搭建】

Ubuntu 20.04环境下部署Elastic Stack 8.18日志系统完整指南 一、环境准备 系统要求 Ubuntu 20.04 LTS硬件配置:4核CPU / 8GB内存 / 100GB硬盘网络:需外网访问权限 1. 基础环境配置 首先安装SSH服务以便远程管理: # 更新软件源 apt u…

Mac电脑 Office 2024 LTSC 长期支持版(Excel、Word、PPT)

Office 2024 mac,是一款是一款专为苹果电脑用户设计的高性能、高安全性的办公套装 集成了Word、Excel、PowerPoint、Outlook等经典应用,为用户提供了一站式的办公解决方案。 不仅继承了Office系列一贯的卓越性能,还在功能性和用户体验上进行…

深入解析 Schema 在不同数据库中的百变面孔

在数据库的世界里,数据是核心资产,但如何高效、有序、安全地组织和理解这些数据?答案就是 Schema(模式或架构)。它如同建筑的图纸、乐队的乐谱,是数据库的设计蓝图和运行规则手册。今天,我们就来…

Python 数据分析与可视化 Day 2 - 数据清洗基础

🎯 今日目标 学会识别和处理缺失数据(NaN)学会删除/填补缺失值清理重复数据修改列类型,准备数据分析 🧼 一、缺失值处理(NaN) ✅ 1. 检查缺失值 import pandas as pd df pd.read_csv("…

3DS中文游戏全集下载 任天堂3DS简介3DS第一方独占游戏推荐

任天堂3DS 的详细介绍,涵盖其硬件特性、核心功能、游戏阵容及历史地位: 3DS游戏全集下载 https://pan.quark.cn/s/dd40e47387e7 https://sink-698.pages.dev/3ds CIA CCA 等格式可用于3DS模拟器和3DS实体机 3DS 是什么? 全称:Nin…

【Python小练习】3D散点图

资产风险收益三维分析 背景 王老师是一名金融工程研究员,需要对多个资产的预期收益、风险(波动率)和与市场的相关性进行综合分析,以便为投资组合优化提供决策依据。 代码实现 import matplotlib.pyplot as plt from mpl_toolk…

安宝特案例丨突破传统手术室,Vuzix AR 眼镜圆满助力全膝关节置换术

在巴西圣保罗医院的手术室里,骨科权威 Ricardo Gobbi医生正戴着 安宝特 Vuzix 智能 AR 眼镜,为一位膝关节炎患者实施全膝关节置换术。与传统手术不同的是,他的视野中实时叠加着骨骼三维模型、切割路径标线和动态数据 —— 这并非科幻场景&…

qt设置文件自动保存-cnblog

步骤: 「工具」->「选项」->「环境」->「Auto-save modified files」。 可开启/关闭自动保存文件功能,还可设置自动保存时间的间隔(最短间隔1分钟)。 钟)。

linux下如何找到dump文件被生成到哪里了

在大多数 Linux 系统中,核心转储文件(core dump)通常由系统自动保存在当前工作目录下,或者由配置决定其保存位置。核心转储文件的默认文件名通常包含进程 ID(PID)和程序名,例如 core.PID 或 cor…

API 调试工具校验 JSON Mock 接口(一):无参请求与基础响应验证

在前后端分离的开发模式中,JSON Mock 工具为前端开发人员在后端接口未就绪时提供了极大便利,能够模拟返回 JSON 数据的 API 接口,实现前端独立开发与测试。而 API 开发调试工具 作为一款强大的接口测试工具,可进一步对这些 Mock 接…

单体架构、微服务架构和分布式架构的区别

. 架构定义与核心特征 1.1 单体架构(Monolithic Architecture) 单体架构是将所有功能模块集中在一个单一代码库中的传统架构模式: 所有功能(UI层、业务逻辑、数据访问)打包为单一部署单元通常使用单一技术栈开发(如Spring Boot、Django等)共享单一数据库实例进程内通信(方法…

如何重新安装 Rust

在开发过程中,我们有时可能需要重新安装 Rust,比如遇到版本冲突、环境配置错误,或者仅仅是想更新到最新版本。本文将详细介绍如何卸载现有 Rust 安装,并重新安装 Rust,同时还会介绍一些常见的配置技巧,帮助…

使用springboot实现过滤敏感词功能

一,在springboot项目的resources目录里创建sensitive-words.text(敏感词文本) 每个词独自一行 列如: 赌博 吸毒 开票 二,在util创建工具类SensitiveFilter package com.nowcoder.community.util;Component public c…

Vue 苍穹外卖

Vue 苍穹外卖 node_modules:当前项目依赖的js包 assets:静态资源存放目录 components:公共组件存放目录 App.vue:项目的主组件,页面的入口文件 main.js:整个项目的入口文件 package.json:项…

评估视觉在CNN 在人类动作识别准确率

大家读完觉得有帮助记得关注和点赞!!! 抽象 本研究使用 COCO 图像语料库的三类子集探索人类动作识别,对从简单的全连接网络到 transformer 架构的模型进行基准测试。二进制 Vision Transformer (ViT) 实现了…

Self-supervised Learning(BERT/GPT/T5)

李宏毅老师《Pre-train Model》 什么是:Self-supervised Learning BERT BERT 能做什么 Mask Input Next Sentence Prediction(not helpful) BERT其它的能力 上述的能力,可以认为是一种填空的能力,那么除了这些,还有哪些有用的能力呢&…

《NuGet:.NET开发的魔法包管理器》

一、NuGet 初相识 在软件开发的广袤天地中,依赖管理始终是一个核心议题。想象一下,在没有高效包管理工具的年代,开发者如同在黑暗中摸索前行。当项目逐渐庞大,所需的外部库和组件日益增多,手动管理这些依赖就如同一场噩…

Vulkan 学习笔记12—深度缓冲

一、3D几何体与深度问题 Z坐标引入 将2D几何体扩展为3D时,需在Vertex结构体中添加glm::vec3 pos表示三维位置,并更新顶点输入描述符格式为VK_FORMAT_R32G32B32_SFLOAT。顶点着色器需接收3D坐标并通过模型-视图-投影矩阵转换为裁剪坐标。 深度冲突问题 当…