Java多线程面试题(一)

Java多线程面试题(一)

  • 前言
  • 1、在 Java 中守护线程和本地线程区别?
  • 2、线程与进程的区别?
  • 3、什么是多线程中的上下文切换?
  • 4、死锁与活锁的区别,死锁与饥饿的区别?
  • 5、Java 中用到的线程调度算法是什么?
  • 6、为什么使用 Executor 框架?
  • 7、在 Java 中 Executor 和 Executors 的区别?
  • 8、如何在 Windows 和 Linux 上查找哪个线程使用的 CPU 时间最长?
  • 9、什么是 Executors 框架?
  • 10、什么是阻塞队列?阻塞队列的实现原理是什么?
  • 11、什么是 Callable 和 Future?
  • 12、什么是 FutureTask?
  • 13、什么是并发容器的实现?
  • 14、多线程同步和互斥有几种实现方法,都是什么?
  • 15、什么是竞争条件?你怎样发现和解决竞争?
  • 16、你将如何使用 thread dump?你将如何分析 Thread dump?
  • 17、为什么我们调用 start()方法时会执行 run()方法?
  • 18、Java 中你怎样唤醒一个阻塞的线程?
  • 19、什么是不可变对象,它对写并发应用有什么帮助?
  • 20、为什么使用 Executor 线程池框架?
  • 总结


前言

最新的 Java 面试题,技术栈涉及 Java 基础、集合、多线程、Mysql、分布式、Spring全家桶、MyBatis、Dubbo、缓存、消息队列、Linux…等等,会持续更新。

如果对老铁有帮助,帮忙免费点个赞,谢谢你的发财手!

1、在 Java 中守护线程和本地线程区别?

Java中任何线程都可以设置为守护线程和用户线程,通过方法 Thread.setDaemon(true);
true 则把该线程设置为守护线程,默认false为用户线程;
要注意的是Thread.setDaemon() 必须在 Thread.start()之前调用,否则运行时会抛出异常。
两者的区别:就是判断虚拟机(JVM)何时离开
用户线程就是如果有任何一个用户线程未结束,Java虚拟机是不会结束的。
守护线程就是如果只剩守护线程未结束,那么Java虚拟机就会结束了。

2、线程与进程的区别?

首先定义不一样:进程是一个在内存中运行的应用程序,而线程是进程中的一个执行任务;
一个线程只可以属于一个进程,但一个进程能包含多个线程, 多个线程可共享数据。

3、什么是多线程中的上下文切换?

是指线程数大于给程序分配的CPU数量时,为了让各个线程都有执行的机会,就需要切换使用CPU;
不同的线程切换使用CPU发生的切换数据等 就是上下文切换。

4、死锁与活锁的区别,死锁与饥饿的区别?

  • 死锁:是指两个或两个以上的进程(或线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
    产生死锁的必要条件:
    1、独占资源:一个资源每次只能给一个进程使用(比如写操作)
    2、占有且申请:进程在申请新的资源的同时,保持对原有资源的占有
    3、不可夺取:资源申请者不能强行从资源占有者手中夺取资源,资源只能由占有者自愿释放
    4、循环等待:线程1等待线程2占有的资源,线程2等待线程1占有的资源,形成了一个进程等待回路。
    典型案例:哲学家共进午餐问题
  • 活锁:任务或者执行者没有被阻塞,由于某些条件没有满足,导致一直重复尝试,失败,尝试,失败。活锁有可能自行解开,死锁则不能。
    饥饿:是指一个可运行的进程被调度器无限期地忽视,而不能被调度执行的情况。

5、Java 中用到的线程调度算法是什么?

有两种调度模型:分时调度模型和抢占式(java默认使用)调度模型。

  • 分时调度模型: 平均分配每个线程占用的 CPU 的时间片。
  • 抢占式调度模型: 让优先级高的线程占用CPU,如果线程优先级相同,那么就随机选择一个线程,可以通过 setPriority(1~10)设置优先级

6、为什么使用 Executor 框架?

Executor是一个多线程管理框架,创建线程的方式有三种Thread、Runnable、Callable
调用 new Thread()创建的线程缺乏管理,被称为野线程,而且可以无限制的创建,线程之间的相互竞争会导致过多占用系统资源而导致系统瘫痪,还有线程之间的频繁交替也会消耗很多系统资源。
接使用 new Thread() 启动的线程不利于扩展,比如定时执行、定期执行、定时定期执行、线程中断等都不便实现。

7、在 Java 中 Executor 和 Executors 的区别?

Executors 工具类的不同方法按照我们的需求创建了不同的线程池,来满足业务的需求。
Executor 接口对象能执行我们的线程任务。
ExecutorService 接口继承了 Executor 接口并进行了扩展,提供了更多的方法我们能获得任务执行的状态并且可以获取任务的返回值。
使用 ThreadPoolExecutor 可以创建自定义线程池。
Future 表示异步计算的结果,他提供了检查计算是否完成的方法,以等待计算的完成,并可以使用 get()方法获取计算的结果。

8、如何在 Windows 和 Linux 上查找哪个线程使用的 CPU 时间最长?

使用 jstack 找出消耗 CPU 最多的线程代码。

9、什么是 Executors 框架?

Executor 框架是一个根据一组执行策略调用,调度,执行和控制的异步任务的框架。
无限制的创建线程会引起应用程序内存溢出,所以创建一个线程池是个更好的的解决方案,因为可以限制线程的数量并且可以回收再利用这些线程,利用Executors 框架可以非常方便的创建一个线程池。

10、什么是阻塞队列?阻塞队列的实现原理是什么?

阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。
这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。
阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素

11、什么是 Callable 和 Future?

Callable 接口类似于 Runnable,从名字就可以看出来了,但是 Runnable 不会返回结果,并且无法抛出返回结果的异常,而 Callable 功能更强大一些,被线程执行后,可以返回值,这个返回值可以被 Future 拿到,也就是说,Future 可以拿到异步执行任务的返回值。
可以认为是带有回调的 Runnable。
Future 接口表示异步任务,是还没有完成的任务给出的未来结果。所以说 Callable 用于产生结果,Future 用于获取结果。

12、什么是 FutureTask?

在 Java 并发程序中 FutureTask 表示一个可以取消的异步运算。它有启动和取消运算、查询运算是否完成和获取运算结果等方法,只有当运算完成的时候结果才能取回,如果运算尚未完成, get 方法将会阻塞。当一个线程需要等待另一个线程把某个任务执行完后它才能继续执行,此时可以使用FutureTask。

13、什么是并发容器的实现?

我们先从并发容器的由来谈起。Java的集合容器框架中,主要有四大类别:List、Set、Queue、Map,我们熟知的这些集合类ArrayList、LinkedList、HashMap这些容器都不是线程安全的,如果有多个线程并发地访问这些容器时,就会出现问题。因此Java提供了同步容器供用户使用。

  • 同步容器可以简单地理解为通过synchronized来实现同步的容器,比如Vector、Hashtable以及SynchronizedList等容器,这样做的代价是削弱了并发性,当多个线程共同竞争容器级的锁时,吞吐量就会降低,因此为了解决同步容器的性能问题,所以才有了并发容器。
  • 并发类容器是专门针对多线程并发设计的,采用了CAS算法和部分代码使用synchronized锁保证线程安全,只对操作的位置进行同步操作,但是其他没有操作的位置其他线程仍然可以访问,提高了程序的吞吐量。
    java.util.concurrent包中提供了多种并发类容器,比如ConcurrentHashMap、CopyOnWriteArrayList CopyOnWriteArraySet等等。
    CAS算法它可以不使用锁而保证多线程安全,所以CAS也是一种无锁算法,也是乐观锁的提现。

14、多线程同步和互斥有几种实现方法,都是什么?

线程同步是指一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。
线程互斥是指当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。线程互斥可以看成是一种特殊的线程同步。
线程间的同步方法大体可分为两类:用户模式和内核模式。顾名思义,内核模式就是指利用系统内核对象的单一性来进行同步,使用时需要切换内核态与用户态,而用户模式就是不需要切换到内核态,只在用户态完成操作。

15、什么是竞争条件?你怎样发现和解决竞争?

在java多线程中,当两个或以上的线程对同一个数据进行操作的时候,可能会产生“竞争条件”的现象。这时候需要加锁,来解决多线程操作同一个数据时可能产生的问题。加锁方式有两种,一h种是Lock对象来对语句快进行加锁,另一种是通过synchronized 关键字来对方法进行加锁。以上两种方法都可以有效解决多线程中存在的竞争条件的问题。

16、你将如何使用 thread dump?你将如何分析 Thread dump?

Thread Dump是非常有用的诊断Java应用问题的工具,
1、可以查找内存泄露;2、可以发现死锁线程。
然后分析Thread Dump的各个部分:
1、头部信息;2、线程类型;3、线程优先级;4、jvm线程id;5、线程状态
注意看这个:

  • 初始化状态(New)
    在调用start()方法之前
  • 就绪状态(Runnable)
    调用了start()方法,该线程就进入就绪状态,只有处于就绪状态的线程才能获得CPU的使用权。
  • 运行状态(Running)
    线程获得CPU的使用权,执行程序代码。
  • 阻塞(超时)状态(Blocked)
    线程因为某些原因放弃 CPU,暂时停止运行。比如执行了某个对象的 wait()方法、或者执行了sleep()方法,或者调用了其他线程的 join()方法。
  • 死亡状态(Dead)
    线程的run()运行结束,调用stop()方法或者在运行过程中出现了未捕获的异常时,线程进入死亡状态Thread Dump是非常有用的诊断Java应用问题的工具,
    1、可以查找内存泄露;2、可以发现死锁线程。
    然后分析Thread Dump的各个部分:
    头部信息;2、线程类型;3、线程优先级;4、jvm线程id;5、线程状态。

17、为什么我们调用 start()方法时会执行 run()方法?

在调用start()方法后,线程并不能立即开始执行run()方法,而是处于就绪状态(Runnable),等待线程调度程序为其分配CPU时间片,并使其进入运行状态(Running),当线程获得CPU资源后,就会自动调用其对应的run()方法,开始执行线程代码。
Thread类中的start()方法实际上是一个异步调用,它会立即返回并继续执行下一条语句,而不会等待线程执行完毕。
但是如果你直接调用 run()方法,它不会创建新的线程,只会把 run 方法当作普通方法去执行 。

18、Java 中你怎样唤醒一个阻塞的线程?

在 Java 中使用 Object 类的 wait()和 notify()方法实现线程阻塞和唤醒。
wait、notify方法是针对对象的,而且必须在 synchronized 块或方法中被调用。
调用wait()方法都会导致线程阻塞,阻塞的同时也会释放该对象的锁,相应地,调用notify()方法则将解除该对象阻塞的线程,但它需要重新获取该对象的锁,直到获取成功才能往下执行。

19、什么是不可变对象,它对写并发应用有什么帮助?

不可变对象是指对象一旦被创建,它的状态(即对象属性值)就不能改变。
比如 String、8种基本类型的包装类等。(不可变对象永远是线程安全的)。

20、为什么使用 Executor 线程池框架?

线程池就是为了管理线程的生命周期,提高效率,优点如下:

  • 1、可以复用线程,从而减少线程对象的反复创建和销毁。
  • 2、可有效控制最大并发线程数,提高系统资源使用率。
  • 3、框架中还有定时、定期、并发数控制等功能。
    综上所述使用线程池框架 Executor 能更好的管理线程、提供系统资源使用率。

总结

都已经看到这里啦,赶紧收藏起来,祝您工作顺心,生活愉快!

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

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

相关文章

【Android12】Monkey压力测试源码执行流程分析

Monkey压力测试源码执行流程分析 Monkey是Android提供的用于应用程序自动化测试、压力测试的测试工具。 其源码路径(Android12)位于 /development/cmds/monkey/部署形式为Java Binary # development/cmds/monkey/Android.bp // Copyright 2008 The Android Open Source Proj…

Leetcoder Day21| 回溯理论基础+组合

语言:Java/Go 回溯理论基础 回溯函数也就是递归函数; 所有回溯法的问题都可以抽象为树形结构; 回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度,都构成的树的深度。 适用的题…

深度学习基础(一)神经网络基本原理

之前的章节我们初步介绍了机器学习相关基础知识,目录如下: 机器学习基础(一)理解机器学习的本质-CSDN博客 机器学习基础(二)监督与非监督学习-CSDN博客 机器学习基础(四)非监督学…

深入理解计算机系统学习笔记

2.3整数运算 有时候会发现两个正数相加会得出一个负数&#xff0c;而比较表达式x<y和比较表达式x-y<0会产生不同的结果。这些属性是由于计算机运算的有限性造成的。理解计算机运算的细微之处能够帮助程序员编写更可靠的代码。 2 .3. 1 无符号加法 原理&#xff1a; 在正…

前端学习---- 前端HTML基本元素的介绍

一&#xff1a;显示相关的HTML基础知识 1. 推荐的前端编写工具 2. VScode的html速写规则&#xff08;从a标签开始再用&#xff09; ①、&#xff01;&#xff1a;代表生成html的基本框架元素 ②、html元素&#xff1a;直接书写html,不需要加<>,按回车会自动生成 ③、{}…

Java之线程池:线程池常用类、接口;线程池执行流程,配置参数,分类

线程池 什么是线程池&#xff1f; 线程池&#xff1a;一种基于池化思想管理和使用线程的机制 线程池常用类和接口 ExecutorService接口&#xff1a;进行线程池的操作访问Executors类&#xff1a;创建线程池的工具类ThreadPoolExecutor及其子类&#xff1a;封装线程池的核心参…

蓝桥杯备战刷题(自用)

1.被污染的支票 #include <iostream> #include <vector> #include <map> #include <algorithm> using namespace std; int main() {int n;cin>>n;vector<int>L;map<int,int>mp;bool ok0;int num;for(int i1;i<n;i){cin>>nu…

ChatGPT为什么会被热炒?

2023年上半年&#xff0c;ChatGPT引起了广泛的热议&#xff0c;对于ChatGPT有多热&#xff0c;不需要我重复了&#xff0c;你可能在网上看到了很多报道&#xff0c;标题如《ChatGPT揭开AI战幔&#xff1a;杀死黄页一样摧毁Google&#xff1f;》和《ChatGPT强势来袭&#xff0c;…

【技术分享】使用nginx完成动静分离➕集成SpringSession➕集成sentinel➕集成seata

&#x1f973;&#x1f973;Welcome 的Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于技术点的相关分享吧 目录 &#x1f973;&#x1f973;Welcome 的Huihuis Code World ! !&#x1f973;&#x1f973; 一、 使用nginx完成动静分离 1.下载…

springboot/ssm高校物品捐赠管理系统Java校园爱心捐赠管理系统web

springboot/ssm高校物品捐赠管理系统Java校园爱心捐赠管理系统web 基于springboot(可改ssm)vue项目 开发语言&#xff1a;Java 框架&#xff1a;springboot/可改ssm vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xf…

JAVA毕业设计129—基于Java+Springboot+thymeleaf的物业管理系统(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootthymeleaf的物业管理系统(源代码数据库)129 一、系统介绍 本项目前后端分离&#xff0c;本系统分为管理员、小区管理员、用户三种角色 1、用户&#xff1a; 登…

可持久化线段树 2

推荐在 cnblogs 上阅读。 可持久化线段树 前言 这个东西之前讲过&#xff0c;但是用得少&#xff0c;很快就忘了。 我又看了我之前的那篇笔记&#xff0c;简直就是胡言乱语。所了解的太浅了。 最近在刷数据结构&#xff0c;于是决定再写一篇。 但是&#xff0c;之前那篇不…

一种简易的多进程文件读写器

目录 1. 前言2. 初步实现3. ParallelFileProcessor 1. 前言 在数据清洗场景下&#xff0c;我们可能需要对一个 .jsonl 文件清洗以得到另一个 .jsonl 文件。一种直观的做法就是逐行读取&#xff0c;逐行清洗&#xff0c;然后逐行写入&#xff0c;这一流程的示意图如下&#xff…

【wails】(6):使用wails做桌面应用开发,使用gin+go-chatglm.cpp进行本地模型运行,在windows上运行成功

1&#xff0c;整体架构说明 主要使用&#xff0c;参考的开源项目是&#xff1a; https://github.com/wailsapp/wails 前端项目&#xff1a; https://github.com/Chanzhaoyu/chatgpt-web 运行模型&#xff1a; https://github.com/Weaxs/go-chatglm.cpp 参考代码&#xff1a; h…

深度神经网络中的计算和内存带宽

深度神经网络中的计算和内存带宽 文章目录 深度神经网络中的计算和内存带宽来源原理介绍分析1&#xff1a;线性层分析2&#xff1a;卷积层分析3&#xff1a;循环层总结 来源 相关知识来源于这里。 原理介绍 Memory bandwidth and data re-use in deep neural network computat…

五.AV Foundation 视频播放 - 标题和字幕

引言 本篇博客主要介绍使用AV Foundation加载视频资源的时候&#xff0c;如何获取视频标题&#xff0c;获取字幕并让其显示到播放界面。 设置标题 资源标题的元数据内容&#xff0c;我们需要从资源的commonMetadata中获取&#xff0c;在加载AVPlayerItem的时候我们已经指定了…

Sentinel微服务流量治理组件实战上

目录 分布式系统遇到的问题 解决方案 Sentinel 是什么&#xff1f; Sentinel 工作原理 Sentinel 功能和设计理念 流量控制 熔断降级 Sentinel工作主流程 Sentinel快速开始 Sentinel资源保护的方式 基于API实现 SentinelResource注解实现 Spring Cloud Alibaba整合…

AIGC 架构:RAG (retrieval augumented generation) 应用可以使用 PostgreSQL 作为向量数据库组件吗?

是的&#xff0c;RAG&#xff08;检索增强生成&#xff09;应用程序可以绝对地使用 PostgreSQL 作为向量数据库&#xff01;事实上&#xff0c;它是一个流行的选择&#xff0c;因为有以下几个优点&#xff1a; 使用 PostgreSQL 和 pgvector 的优点&#xff1a; 集成解决方案&…

【颠覆旧知识】JS的原型链搜索原则;

最近准备面试&#xff0c;梳理以前的知识&#xff0c;发现我以前对原型链的搜索原则理解一直不完全对。 以前的理解&#xff1a; “在当前对象未找到该属性&#xff0c;就一直向上查找&#xff0c;找到就停止并返回该数据&#xff0c;如果直到object的原型也没找到&#xff0c…

介绍 PIL+IPython.display+mtcnn for 音视频读取、标注

1. nn.NLLLoss是如何计算误差的? nn.NLLLoss是负对数似然损失函数&#xff0c;用于多分类问题中。它的计算方式如下&#xff1a;首先&#xff0c;对于每个样本&#xff0c;我们需要将其预测结果通过softmax函数转换为概率分布。softmax函数可以将一个向量映射为一个概率分布&…