Java并发面试题汇总

news2024/11/27 18:40:24

文章目录

  • 线程
    • 什么是线程和进程?
    • 请简要描述线程与进程的关系,区别及优缺点?
    • 程序计数器、虚拟机栈、虚拟机栈、堆和方法区
    • 如何创建线程?
    • 线程的生命周期
    • 什么是线程上下文切换?
    • Thread#sleep() 方法和 Object#wait() 方法对比
    • 为什么 wait() 方法不定义在 Thread 中?
    • 为什么 sleep() 方法定义在 Thread 中?
    • 可以直接调用 Thread 类的 run 方法吗?
    • java线程通信的方式有哪些?
    • java中wait、 notify、notifyall作用?
  • 多线程
    • 并发与并行的区别
    • 同步和异步的区别
    • 单核 CPU 支持 Java 多线程吗?
    • 使用多线程可能带来什么问题?
    • 如何理解线程安全和不安全?
  • 线程池
    • 什么是线程池?
    • 为什么要用线程池?(线程池的好处)
    • 如何创建线程池?
    • java并发库(ThreadPoolExecutor)提供了哪些线程池实现?有什么区别?
    • 线程池常见参数有哪些?如何解释?
    • 线程池的核心线程会被回收吗?
    • 线程池的拒绝策略有哪些?
    • 如果不允许丢弃任务任务,应该选择哪个拒绝策略?
    • CallerRunsPolicy 拒绝策略有什么风险?如何解决?
    • 线程池常用的阻塞队列有哪些?
    • 线程池处理任务的流程了解吗(线程池的工作原理)?
    • 线程池中线程异常后,销毁还是复用?
    • 如何给线程池命名?
    • 如何设定线程池的大小?
  • 死锁
    • 什么是线程死锁?
    • 产生死锁的四个必要条件
    • 如何检测死锁?
    • 如何预防和避免线程死锁?
  • 虚拟线程
    • 什么是虚拟线程(协程)?
    • 虚拟线程有什么优点和缺点?
  • JMM(JAVA内存模型)
  • volatile 关键字
    • 如何保证变量的可见性?
    • 如何禁止指令重排序?
    • volatile 可以保证原子性么?
  • 乐观锁和悲观锁
    • 什么是悲观锁?
    • 什么是乐观锁?
    • 如何实现乐观锁?
    • CAS原理
    • Java 中 CAS 是如何实现的?
    • CAS 算法存在哪些问题?
  • ThreadLocal
    • ThreadLocal 有什么用?为什么要ThreadLocal?
    • ThreadLocal 底层原理?
    • 为什么在使用ThreadLocal要使用弱引用来防止内存泄漏?
    • ThreadLocal 内存泄露问题是怎么导致的,以及该怎么解决?
    • java父子线程之间怎么传递数据(了解InheritableThreadLocal吗?)
    • ThreadLocal缺点
  • synchronized 关键字
    • synchronized 是什么?有什么用?
    • 如何使用 synchronized?
    • 构造方法可以用 synchronized 修饰么?
    • synchronized 底层原理了解吗?
    • JDK1.6 之后的 synchronized 底层做了哪些优化?锁升级原理了解吗?
    • synchronized 和 volatile 有什么区别?
  • ReentrantLock
    • ReentrantLock 是什么?
    • synchronized 和 ReentrantLock 有什么区别?
    • 可中断锁和不可中断锁有什么区别?
  • ReentrantReadWriteLock
    • ReentrantReadWriteLock 是什么?
    • ReentrantReadWriteLock 适合什么场景?
    • 线程持有读锁还能获取写锁吗?
    • 读锁为什么不能升级为写锁?
  • StampedLock
    • StampedLock 是什么?
  • Atomic原子类
    • 有哪些Atomic原子类?
  • Future
    • Future 类有什么用?
    • Callable 和 Future 有什么关系?
    • CompletableFuture 类有什么用?
  • AQS相关
    • AQS 是什么?
    • AQS 的原理是什么?
    • AQS的应用
    • Semaphore有什么用以及原理?
    • CountDownLatch 有什么用以及原理?
    • CyclicBarrier 有什么用以及原理?

线程

什么是线程和进程?

进程:进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。

线程:线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。

请简要描述线程与进程的关系,区别及优缺点?

下图是 Java 内存区域,通过下图我们从 JVM 的角度来说一下线程和进程之间的关系。
在这里插入图片描述

从上图可以看出:一个进程中可以有多个线程,多个线程共享进程的堆和方法区 (JDK1.8 之后的元空间)资源,但是每个线程有自己的程序计数器、虚拟机栈 和 本地方法栈

总结: 线程是进程划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。线程执行开销小,但不利于资源的管理和保护;而进程正相反。

程序计数器、虚拟机栈、虚拟机栈、堆和方法区

程序计数器:

  • 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
  • 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。

虚拟机栈: 每个 Java 方法在执行之前会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。

本地方法栈: 和虚拟机栈所发挥的作用非常相似,区别是:虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。 在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一。

堆和方法区是所有线程共享的资源,其中堆是进程中最大的一块内存,主要用于存放新创建的对象 (几乎所有对象都在这里分配内存),方法区主要用于存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

如何创建线程?

  1. 继承Thread类,重写run方法
  2. 实现Runnable接口,并重写run方法
  3. 实现Callable接口
  4. 可以通过Executors创建线程池,也可以自定义线程池
  5. 使用CompleteFuture类

不过,这些方式其实并没有真正创建出线程。准确点来说,这些都属于是在 Java 代码中使用多线程的方法。

严格来说,Java 就只有一种方式可以创建线程,那就是通过new Thread().start()创建。不管是哪种方式,最终还是依赖于new Thread().start()。

线程的生命周期

Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种不同状态的其中一个状态:

  • NEW: 初始状态,线程被创建出来但没有被调用 start() 。
  • RUNNABLE: 运行状态,线程被调用了 start()等待运行的状态。
  • BLOCKED:阻塞状态,需要等待锁释放。
  • WAITING:等待状态,表示该线程需要等待其他线程做出一些特定动作(通知或中断)
  • TIME_WAITING:超时等待状态,可以在指定的时间后自行返回而不是像 WAITING 那样一直等待。
  • TERMINATED:终止状态,表示该线程已经运行完毕。

注意:

  • 线程创建之后它将处于 NEW(新建) 状态,调用 start() 方法后开始运行,线程这时候处于 READY(可运行) 状态。可运行状态的线程获得了 CPU 时间片(timeslice)后就处于 RUNNING(运行) 状态。

  • 在操作系统层面,线程有 READY 和 RUNNING 状态;而在 JVM 层面,只能看到 RUNNABLE 状态,所以 Java 系统一般将这两个状态统称为 RUNNABLE(运行中) 状态 。

  • 当线程执行 wait()方法之后,线程进入 WAITING(等待) 状态。进入等待状态的线程需要依靠其他线程的通知才能够返回到运行状态。

  • TIMED_WAITING(超时等待) 状态相当于在等待状态的基础上增加了超时限制,比如通过 sleep(long millis)方法或 wait(long millis)方法可以将线程置于 TIMED_WAITING 状态。当超时时间结束后,线程将会返回到 RUNNABLE 状态。

  • 当线程进入 synchronized 方法/块或者调用 wait 后(被 notify)重新进入 synchronized 方法/块,但是锁被其它线程占有,这个时候线程就会进入 BLOCKED(阻塞) 状态。

  • 线程在执行完了 run()方法之后将会进入到 TERMINATED(终止) 状态

加粗样式

什么是线程上下文切换?

线程在执行过程中会有自己的运行条件和状态(也称上下文),比如上文所说到过的程序计数器,栈信息等。当出现如下情况的时候,线程会从占用 CPU 状态中退出。

  • 主动让出 CPU,比如调用了 sleep(), wait() 等。
  • 时间片用完,因为操作系统要防止一个线程或者进程长时间占用 CPU 导致其他线程或者进程饿死。
  • 调用了阻塞类型的系统中断,比如请求 IO,线程被阻塞。
  • 被终止或结束运行

这其中前三种都会发生线程切换,线程切换意味着需要保存当前线程的上下文,留待线程下次占用 CPU 的时候恢复现场。并加载下一个将要占用 CPU 的线程上下文。这就是所谓的 上下文切换。

Thread#sleep() 方法和 Object#wait() 方法对比

共同点: 两者都可以暂停线程的执行。
区别:

  • sleep() 方法没有释放锁,而 wait() 方法释放了锁 。
  • wait() 通常被用于线程间交互/通信,sleep()通常被用于暂停执行。
  • wait() 方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的 notify()或者 notifyAll() 方法。sleep()方法执行完成后,线程会自动苏醒,或者也可以使用 wait(long timeout) 超时后线程会自动苏醒。
  • sleep() 是 Thread 类的静态本地方法,wait() 则是 Object 类的本地方法。

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

wait() 是让获得对象锁的线程实现等待,会自动释放当前线程占有的对象锁。每个对象(Object)都拥有对象锁,既然要释放当前线程占有的对象锁并让其进入 WAITING 状态,自然是要操作对应的对象(Object)而非当前的线程(Thread)。

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

因为 sleep() 是让当前线程暂停执行,不涉及到对象类,也不需要获得对象锁。

可以直接调用 Thread 类的 run 方法吗?

调用 start() 方法方可启动线程并使线程进入就绪状态,而直接执行 run() 方法的话不会以多线程的方式执行,会把 run() 方法当成一个 main 线程下的普通方法去执行,并不会在某个线程中执行它。

java线程通信的方式有哪些?

线程间通信方式,从实现本质来讲,主要可以分为两大类共享内存和消息传递。

  1. 共享变量: 线程之间可以通过共享变量来进行通信。不同的线程可以共享同一个变量,并在变量上进行读写操作。需要注意的是,共享变量可能会引发线程安全问题,需要通过同步机制来确保线程安全。
  2. 锁机制: 锁机制是一种常用的线程同步机制,可以保证在同一时间只有一个线程能够访问共享资源。Java提供了多种锁类型,如 synchronized 关键字、ReentrantLock 类等。
  3. 条件变量:条件变量是一种线程间通信机制,它用于在一个共享资源上等待某个条件的成立。Java 提供了 Condition 接口来支持条件变量的实现,在使用 Condition 时需要先获取锁,然后调用 await() 方法等待条件成立,当条件成立时可以通过 signal() 或 signalAll() 方法唤醒等待该条件的线程。
  4. 信号量:信号量是一种常见的线程同步机制,可用于控制多个线程对共享资源的访问。Java 提供了 Semaphore 类来实现信号量,Semaphore 类有两个常用的方法 acquire() 和 release(),分别用于获取和释放信号量。
  5. 管道:管道是一种用于线程间通信的高级机制,它可以实现一个线程向另一个线程传送数据。Java 提供了 PipedInputStream 和 PipedOutputStream 两个类来支持管道的实现,其中 PipedInputStream 用于读取数据,PipedOutputStream 用于写入数据。

java中wait、 notify、notifyall作用?

这三个都属于Objecy内中定义的方法,主要用于线程之间的通信和同步,且需要在synchronized修饰的方法或同步块中使用。

  • wait()使得当前线程进入等待状态,且会释放锁
  • notify()会随机唤醒一个调用wait后等待的线程
  • notifyall()会唤醒所有调用wait等待的线程。

多线程

并发与并行的区别

  • 并发:两个及两个以上的作业在同一 时间段 内执行。
  • 并行:两个及两个以上的作业在同一 时刻 执行。
    最关键的点是:是否是 同时 执行

同步和异步的区别

  • 同步:发出一个调用之后,在没有得到结果之前, 该调用就不可以返回,一直等待。
  • 异步:调用在发出之后,不用等待返回结果,该调用直接返回。

单核 CPU 支持 Java 多线程吗?

单核 CPU 是支持 Java 多线程的。操作系统通过时间片轮转的方式,将 CPU 的时间分配给不同的线程。尽管单核 CPU 一次只能执行一个任务,但通过快速在多个线程之间切换,可以让用户感觉多个任务是同时进行的。

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

并发编程的目的就是为了能提高程序的执行效率进而提高程序的运行速度,但是并发编程并不总是能提高程序运行速度的,而且并发编程可能会遇到很多问题,比如:内存泄漏、死锁、线程不安全等等。

如何理解线程安全和不安全?

  • 线程安全指的是在多线程环境下,对于同一份数据,不管有多少个线程同时访问,都能保证这份数据的正确性和一致性。
  • 线程不安全则表示在多线程环境下,对于同一份数据,多个线程同时访问时可能会导致数据混乱、错误或者丢失。

线程池

什么是线程池?

线程池就是管理一系列线程的资源池。当有任务要处理时,直接从线程池中获取线程来处理,处理完之后线程并不会立即被销毁,而是等待下一个任务。

为什么要用线程池?(线程池的好处)

  • 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  • 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  • 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

如何创建线程池?

  • 通过ThreadPoolExecutor构造函数来创建(推荐)。
  • 通过 Executor 框架的工具类 Executors 来创建。

通过Executors工具类可以创建多种类型的线程池

  • FixedThreadPool:固定线程数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。
  • SingleThreadExecutor: 只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。
  • CachedThreadPool: 可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务执行完毕后,将返回线程池进行复用。
  • ScheduledThreadPool:给定的延迟后运行任务或者定期执行任务的线程池。

java并发库(ThreadPoolExecutor)提供了哪些线程池实现?有什么区别?

  • newFixedThreadPool:线程数固定, 核心线程和最大线程一致,keepAiveTime 是0, 队列是无界队列,所以可能出现OOM 。仅用于提交相对稳定且数量确定的任务场景。
  • newWorkStealingPool: 线程数就是服务器可用处理核心数,并行数是核心数-1,每个线程都有自己的双端队列,当自己的任务处理完毕后,可以去别的线程队列尾部拿任务执行,加快任务执行速率。
  • newSingleThreadExecutor: 就一个线程,配置的是无界队列,保证任务是按序执行的。
  • newCachedTheadPool: 核心线程数为0&#

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

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

相关文章

【解压即玩】PC端最好用最漂亮的前端CoinOPS整合包186G 复古带遮罩和滤镜,怀旧拉满

这是大神做的一个整合包,让游戏界面更加的漂亮,如图,下面是游戏选择画面,右侧是滚动的圆盘,左侧显示游戏的画面: 实际游戏时的界面是这样的: 应当是目前最漂亮的游戏界面了。之前有人说在电脑上…

sp eric靶机

扫描IP 端口扫描 nmap 192.168.111.146 -p- -sV 目录扫描 # 使用命令 dirsearch -u "http://192.168.111.146" 访问靶机IP地址 拼接访问 admin.php ,发现登录框界面,尝试sql注入,弱口令等,没有结果 看看 .git &#…

【C语言篇】C语言常考及易错题整理DAY2

文章目录 C语言常考及易错题整理选择题编程题至少是其他数字两倍的最大数两个数组的交集图片整理寻找数组的中心下标多数元素除自身以外数组的乘积不使用加减乘除求两个数的加法 C语言常考及易错题整理 选择题 下列 for 循环的次数为( ) for(int i 0…

高可用keepalived详解---干货满满(企业应用示例)

目录 一、master/master 的 Keepalived 双主架构 1.1 ka1部署 1.2 ka2部署 1.3 重启测试 二、实现ipvs高可用 (keepalivedlvs) 2.1 ipvs的相关配置 2.1.1 虚拟服务器配置架构 2.1.2 virtual server (虚拟服务器)的定义格式 2.1.3 虚拟服务器…

四十、大数据技术之Kafka3.x(3)

🌻🌻 目录 一、Kafka Broker1.1 Kafka Broker工作流程1.1.1 Zookeeper 存储的Kafka信息1.1.2 Kafka Broker 总体工作流程1.1.3 Broker 重要参数 1.2 生产经验——节点服役和退役1.2.1 服役新节点1.2.2 退役旧节点 1.3 Kafka 副本1.3.1 副本基本信息1.3.2…

线程知识及编程

线程定义 在Python中,想要实现多任务还可以使用多线程来完成。 为什么使用多线程? 进程是分配资源的最小单位 , 一旦创建一个进程就会分配一定的资源 , 就像跟两个人聊QQ就需要打开两个QQ软件一样是比较浪费资源的 . 线程是程序执行的最小单位 , 实际…

企业应该如何准备 EcoVadis 审核?

企业准备 EcoVadis 审核可以参考以下步骤: 注册:在网上注册并提供公司的相关信息,包括法律实体名称、国家和地区、企业规模和行业等。如果是受客户邀请参加评估,需按照邀请邮件中的链接进行注册,并确保客户能随时获知评…

【ML】强化学习(Reinforcement Learning)及其拆解

【ML】强化学习(Reinforcement Learning) 1. RL Outline 强化学习(Reinforcement Learning)概述1.1 RL的基本框架 2. RL 引入:从这个小游戏开始3. Policy Gradient 方法4. Actor-Critic 方法5. [奖励塑形(R…

(第二十六天)

上午 1、web01与web02服务器搭建 ip:10.0.0.11 systemctl stop filewalld systemctl disable firewalld setenforce 0 vim /etc/selinux/config SELINUX disabled yum -y install nginx echo "web----------01" > /usr/share/nginx/html/index.h…

力扣热题100_二叉树_230_二叉搜索树中第K小的元素

文章目录 题目链接解题思路解题代码 题目链接 230. 二叉搜索树中第K小的元素 给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 小的元素(从 1 开始计数)。 示例 1: 输入&#xff1a…

图论:欧拉路

欧拉路是什么 什么?你对这个名字感到很陌生?再看看是图论的内容,感觉是不是很难?其实一点也不难,这就是生活中的一笔画问题,也就是不重复的经过每一条边并可以访问所有的点,先看看这个图&#…

Python字符串格式化方法输出到控制台

python打印是这样的,我希望resource_id能够对齐输出: 3种格式化方法 %格式化 >>> pi3.141592653589793 >>> e2.718281828459045 >>> print("pi%.2f e%.3f" % (pi, e) ) pi3.14 e2.718“”.format()格式化 >…

操作系统(线程管理-通过条件变量实现消费者与生产者模型)

生产者与消费者模型 生产者:生产数据的线程,这类的线程负责从用户端、客户端接收数据,然后把数据Push到存储中介。 消费者:负责消耗数据的线程,对生产者线程生产的数据进行(判断、筛选、使用、响应、存储&…

x264 编码器 SSIM 算法源码分析

SSIM SSIM(Structural Similarity Index)是一种用于衡量两幅图像之间视觉相似度的指标。它不仅考虑了图像的亮度、对比度和饱和度,还考虑了图像的结构信息。SSIM的值介于-1到1之间,值越接近1表示两幅图像越相似。 SSIM是基于以下三个方面来计算的: 亮度(Luminance):比…

【Hot100】LeetCode—560. 和为 K 的子数组

目录 1- 思路前缀和 2- 实现⭐560. 和为 K 的子数组——题解思路 3- ACM 实现 原题链接:560. 和为 K 的子数组 1- 思路 前缀和 ① 借助 HashMap 存储前缀和:Key 为对应的前缀和,Value 为对应的出现次数 hm 初始化放入 (0,1) 代表和为 0 的情…

linux--chrony时间同步以及局域网同步

文章目录 注意Chrony介绍Chrony 支持的系统与联系方式Chrony Git 仓库环境准备服务端确认是否安装chrony如果没有安装,那就执行以下命令进行安装配置文件/etc/chrony.conf命令参数讲解基本用法选项命令系统时钟命令时间源命令NTP 访问命令执行命令参考 客户端确认是…

Java中等题-乘积最大子数组(力扣)

给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续 子数组 (该子数组中至少包含一个数字),并返回该子数组所对应的乘积。 测试用例的答案是一个 32-位 整数。 示例 1: 输入: nums [2,3,-2,4] 输出: 6 解释: 子数组 […

Telemark电源TT-6E-BEAM SOURCE操作手侧含电路图接线

Telemark电源TT-6E-BEAM SOURCE操作手侧含电路图接线

详解LVS-dr模式

什么是LVS-dr模式 图解 在LVS-DR模式下,负载均衡器(也称为调度器)接收来自客户端的请求,并根据预设的调度算法将请求转发给后端的真实服务器(也称为RS)。真实服务器处理完请求后,直接将响应返回…

Jetpack Compose实战教程(六)

Jetpack Compose实战教程(六) 第六章 没有了margin,如何区分外边距?内边距? 文章目录 Jetpack Compose实战教程(六)一、前言二、本章目标三、开始编码3.1 特殊情况下的margin3.2 使用padding设…