面试_多线程

线程池

线程池的参数有哪些

线程池七大参数分别是corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler

  1. corePoolSize:线程池中常驻核心线程数
  2. maximumPoolSize:线程池能够容纳同时执行的最大线程数
  3. keepAliveTime:多余的空闲线程存活时间
  4. unit:keepAliveTime的时间单位
  5. workQueue:任务队列,被提交但尚未执行的任务
  6. threadFactory:表示生成线程池中的工作线程的线程工厂
  7. handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时如何拒绝。

线程池都有哪几种工作队列

  1. ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
  2. LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列
  3. SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool(5)使用了这个队列。
  4. PriorityBlockingQueue:一个具有优先级的无限阻塞队列

四种线程池的创建

  1. newCachedThreadPool 创建一个可缓存线程池
  2. newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数。
  3. newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
  4. newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务。

线程池的优点?

  1. 重用存在的线程,减少对象创建销毁的开销。
  2. 可有效的控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
  3. 提供定时执行、定期执行、单线程、并发数控制等功能。

如果你提交任务时,线程池队列已满,这时会发生什么

这里区分一下:

1)如果使用的是无界队列 LinkedBlockingQueue,也就是无界队列的话,没关系,继续添加任务到阻塞队列中等待执行,因为LinkedBlockingQueue可以近乎认为是一个无穷大的队列,可以无限存放任务

2)如果使用的是有界队列比如ArrayBlockingQueue,任务首先会被添加到ArrayBlockingQueue中,ArrayBlockingQueue满了,会根据maximumPoolSize的值增加线程数量,如果增加了线程数量还是处理不过来,ArrayBlockingQueue继续满,那么则会使用拒绝策略RejectedExecutionHandler处理满了的任务,默认是AbortPolicy

并发原理

并发编程三要素?

  1. 原子性:原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行。
  2. 可见性:可见性指多个线程操作一个共享变量时,其中一个线程对变量进行修改后,其他线程可以立即看到修改的结果。
  3. 有序性:有序性,即程序的执行顺序按照代码的先后顺序来执行。

实现可见性的方法有哪些?

synchronized或者Lock:保证同一个时刻只有一个线程获取锁执行代码,锁释放之前把最新的值刷新到主内存,实现可见性。

创建线程的有哪些方式?

  1. 继承Thread类创建线程类
  2. 通过Runnable接口创建线程类
  3. 通过Callable和Future创建线程
  4. 通过线程池创建

创建线程的三种方式的对比?

(1)采用实现Runnable、Callable接口的方式创建多线程。

优势是:

  1. 线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。

  2. 在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。

劣势是:

  1. 编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。

(2)使用继承Thread类的方式创建多线程

优势是:

  1. 编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。

劣势是:

  1. 线程类已经继承了Thread类,所以不能再继承其他父类。

(3)Runnable和Callable的区别

  1. Callable规定(重写)的方法是call(),Runnable规定(重写)的方法是run()。
  2. Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
  3. Call方法可以抛出异常,run方法不可以。
  4. 运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。

什么是Future?

在并发编程中,我们经常用到非阻塞的模型,在之前的多线程的三种实现中,不管是继承thread类还是实现runnable接口,都无法保证获取到之前的执行结果。通过实现Callback接口,并用Future可以来接收多线程的执行结果。

Future表示一个可能还没有完成的异步任务的结果,针对这个结果可以添加Callback以便在任务执行成功或失败后作出相应的操作。

什么是AQS

AQS是AbustactQueuedSynchronizer的简称,它是一个Java提高的底层同步工具类,用一个int类型的变量表示同步状态,并提供了一系列的CAS操作来管理这个同步状态。

AQS是一个用来构建锁和同步器的框架,使用AQS能简单且高效地构造出应用广泛的大量的同步器,比如我们提到的ReentrantLock,Semaphore,其他的诸如ReentrantReadWriteLock,SynchronousQueue,FutureTask等等皆是基于AQS的。sleep方法和wait方法有什么区别?

sleep方法和wait方法都可以用来放弃CPU一定的时间,不同点在于如果线程持有某个对象的监视器,sleep方法不会放弃这个对象的监视器,wait方法会放弃这个对象的监视器

ThreadLocal是什么?有什么用?

ThreadLocal是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不通的变量值完成操作的场景。

简单说ThreadLocal就是一种以空间换时间的做法,在每个Thread里面维护了一个以开地址法实现的ThreadLocal.ThreadLocalMap,把数据进行隔离,数据不共享,自然就没有线程安全方面的问题了。

ConcurrentHashMap的并发度是什么

ConcurrentHashMap的并发度就是segment的大小,默认为16,这意味着最多同时可以有16条线程操作ConcurrentHashMap,这也是ConcurrentHashMap对Hashtable的最大优势,任何情况下,Hashtable能同时有两条线程获取Hashtable中的数据吗?

死锁的因素

互斥、不可抢占、请求并保持、循环等待

破坏其中一个因素即可解除死锁

怎么唤醒一个阻塞的线程

如果线程是因为调用了wait()、sleep()或者join()方法而导致的阻塞,可以中断线程,并且通过抛出InterruptedException来唤醒它;

如果线程遇到了IO阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接接触到操作系统。

ThreadLocal了解多少

线程局部变量

sleep() 方法和 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 方法吗?

这是另一个非常经典的 Java 多线程面试问题,而且在面试中会经常被问到。很简单,但是很多人都会答不上来!

new 一个 Thread,线程进入了新建状态。调用 start()方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。 start() 会执行线程的相应准备工作,然后自动执行 run() 方法的内容,这是真正的多线程工作。 但是,直接执行 run() 方法,会把 run() 方法当成一个 main 线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。

总结: 调用 start() 方法方可启动线程并使线程进入就绪状态,直接执行 run() 方法的话不会以多线程的方式执行。

线程中的关键词

synchronized的作用?

在Java中,synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行。

synchronized既可以加在一段代码上,也可以加在方法上。

volatile关键字的作用

对于可见性,Java提供了volatile关键字来保证可见性。

当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。

从实践角度而言,volatile(具有可见性和有序性)的一个重要作用就是和CAS结合,保证了原子性,详细的可以参见 java.util.concurrent.atomic 包下的类,比如AtomicInteger。

synchronized和ReentrantLock的区别

synchronized是和 if、else、for、while 一样的关键字,ReentrantLock是类,这是二者的本质区别。

既然ReentrantLock是类,那么它就提供了比synchronized更多更灵活的特性,可以被继承、可以有方法、可以有各种各样的类变量,ReentrantLock比synchronized的扩展性体现在几点上:

  1. ReentrantLock可以对获取锁的等待时间进行设置,这样就避免了死锁
  2. ReentrantLock可以获取各种锁的信息
  3. ReentrantLock可以灵活地实现多路通知

另外,二者的锁机制其实也是不一样的。ReentrantLock底层调用的是Unsafe的park方法加锁,synchronized操作的应该是对象头中mark word,这点我不能确定。

线程B怎么知道线程A修改了变量

  • volatile修饰变量
  • synchronized修饰修改变量的方法
  • wait/notify
  • while轮询

CAS

什么是CAS

CAS是compare and swap的缩写,即我们所说的比较交换。

cas是一种基于锁的操作,而且是乐观锁。在java中锁分为乐观锁和悲观锁。悲观锁是将资源锁住,等一个之前获得锁的线程释放锁之后,下一个线程才可以访问。而乐观锁采取了一种宽泛的态度,通过某种方式不加锁来处理资源,比如通过给记录加version来获取数据,性能较悲观锁有很大的提高。

CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存地址里面的值和A的值是一样的,那么就将内存里面的值更新成B。CAS是通过无限循环来获取数据的,若果在第一轮循环中,a线程获取地址里面的值被b线程修改了,那么a线程需要自旋,到下次循环才有可能机会执行。

java.util.concurrent.atomic 包下的类大多是使用CAS操作来实现的(AtomicInteger,AtomicBoolean,AtomicLong)

CAS的问题

(1)CAS容易造成ABA问题

一个线程a将数值改成了b,接着又改成了a,此时CAS认为是没有变化,其实是已经变化过了,而这个问题的解决方案可以使用版本号标识,每操作一次version加1。在java5中,已经提供了AtomicStampedReference来解决问题。

(2) 不能保证代码块的原子性

CAS机制所保证的知识一个变量的原子性操作,而不能保证整个代码块的原子性。比如需要保证3个变量共同进行原子性的更新,就不得不使用synchronized了。

(3)CAS造成CPU利用率增加

之前说过了CAS里面是一个循环判断的过程,如果线程一直没有获取到状态,cpu资源会一直被占用。

synchronized、volatile、CAS比较

  • synchronized 是悲观锁,属于抢占式,会引起其他线程阻塞。
  • volatile 提供多线程共享变量可见性禁止指令重排序优化(内存屏障,汇编层次)。
  • CAS 是基于冲突检测的乐观锁(非阻塞)

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

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

相关文章

Salia PLCC cPH2 远程命令执行漏洞(CVE-2023-46359)

漏洞描述 Salia PLCC cPH2 v1.87.0 及更早版本中存在一个操作系统命令注入漏洞,该漏洞可能允许未经身份验证的远程攻击者通过传递给连接检查功能的特制参数在系统上执行任意命令。 产品界面 fofa语法 "Salia PLCC" POC GET /connectioncheck.php?ip1…

前端开发之DNS协议

上一篇👉: 前端开发之计算机网络模型认识 文章目录 DNS协议详介绍1. DNS 协议概述2. DNS协议与TCP/UDP3. DNS查询过程4. 迭代与递归查询5. DNS记录与报文结构资源记录类型对比 6. 总结 DNS协议详介绍 1. DNS 协议概述 DNS(Domain Name System&#xf…

如何使用React的Context API来实现跨组件的状态共享?

在React中,Context API是一种用于跨组件共享状态的方法。以下是使用React的Context API实现跨组件状态共享的基本步骤: 创建Context:首先,你需要创建一个Context对象。可以使用React.createContext()方法来创建一个新的Context实…

UVa12227/LA4618 Wormholes

UVa12227/LA4618 Wormholes 题目链接题意分析测试数据AC 代码 题目链接 本题是2009年icpc欧洲区域赛西北欧赛区的j题 UVA - 12227 Wormholes 题意 你有一艘星际飞船,飞船运行速度为1,打算从坐标a旅行到坐标b(出发时刻为0)&#x…

线程池的艺术:深度解析Java多线程并发性能的优化之道

1. 引言 在高并发的Java应用开发中,线程池作为管理和复用线程资源的核心机制,扮演着举足轻重的角色。合理、高效地使用线程池不仅能减少资源消耗、提高系统响应速度,还能有效控制并发线程数量,保证系统的稳定性和性能。 2. 线程池的基本概念与优势 线程池是一种管理和复用…

发论文idea来了!强化学习+Transformer,29个创新点汇总

基于Transformer的强化学习(TRL)是一种利用Transformer模型架构来改进和增强强化学习算法性能的方法。 这种方法通过结合Transformer模型强大的表示能力和强化学习的决策优化框架,显著提升了智能体的学习能力和适应能力,为我们解…

dockerfile文件的中的命令

# 基础镜像 FROM registry.cn-beijing.aliyuncs.com/205erp/myopenjdk:8.6 # 设置工作目录 WORKDIR /opt # 拷贝jar包到工作目录 COPY target/*.jar app.jar RUN ls # 设置暴漏的端口 EXPOSE 8080 # 启动jar包 CMD java ${JAVA_TOOL_OPTIONS} -jar app.jar

N7745A Keysight 是德 多端口光功率计 简述

N7745A光功率计专为表征多端口光器件而设计,适用于多路复用器、PON分路器、波长选择开关(WSS)和ROADM等多端口器件的测试。它可以节省通道空间,通过LAN或USB连接进行并行编程,集成多种设备到单一设置,提高了…

Android C++系列:函数知识知多少

1. 背景 函数可以理解为功能的封装,很基础的功能单元,但是因为它虽然看似简单,但是里面涉及了不少知识点和技巧,我们花一篇文章来整理。 2. 函数定义 函数有以下几部分定义: 返回类型函数名称形参列表函数体 函数…

企业设备管理现状与解决方案

在当今企业运营中,设备管理作为保障生产稳定、提升效率的重要环节,其复杂性和挑战性日益凸显。无论是生产车间、石油化工、物业小区,还是消防器材、建筑施工等领域,都面临着设备故障频发、维修流程繁琐等共性问题。 为了帮助企业…

Shell编程练习:掌握命令行的魔法

1、编写一个 shell 脚本,它把第二个位置参数及其以后的各个参数指定的文件复制到第一个位置参数指定的目录中。 #!/bin/bash# 检查是否提供了至少两个参数 if [ "$#" -lt 2 ]; thenecho "使用方法: $0 目标目录 文件..."exit 1 fi# 第一个位置…

6.19作业

TCP服务器 #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <arpa/inet.h> #include <netinet/in.h> #include <string.h>#define PORT 8888 #define IP "192.168.124.39&q…

VUE3实现个人网站模板源码

文章目录 1.设计来源1.1 网站首页页面1.2 个人工具页面1.3 个人日志页面1.4 个人相册页面1.5 给我留言页面 2.效果和源码2.1 动态效果2.2 目录结构 源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xcLeigh 文章地址&#xff1…

对比4090及4090D:国区“特供”与原版相比有何区别?

2023年12月28日 英伟达宣布正式发布GeForce RTX 4090D&#xff0c;对比于一年前上市的4090芯片&#xff0c;两者的区别与差异在哪&#xff1f;而在当前比较火热的大模型推理、AI绘画场景方面 两者各自的表现又如何呢&#xff1f; 规格与参数信息对比现在先来看看GeForce RT…

SCI绘图【1】-不同颜色表示密度和差异--密度图

参考资料&#xff1a;密度图&#xff08;Density Plot&#xff09; - 数据可视化图表 - 数字孪生百科 密度图是快速观察变量数值分布的有效方法之一。通常情况下&#xff0c;会根据两个变量将平面绘图区域分为非常多的子区域&#xff0c;之后以不同颜色表示落在该区域上样本的…

揭秘!家用空气净化器针对“毛絮、灰尘”的制胜秘诀是什么?

亲爱的朋友们&#xff01;作为一个家庭主妇&#xff0c;我想和大家聊聊我日常生活中那些让人头疼的飞尘和毛絮问题。 每天忙得团团转&#xff0c;累得腰酸背痛&#xff0c;但家里仍然飘着那些烦人的飞尘和毛絮。它们就像一群顽皮的小精灵&#xff0c;四处飞舞&#xff0c;怎么…

《2024攻防演练必修高危漏洞集合》

1 漏洞汇总数据 以下数据针对自2024年3月以来截止到目前在攻防演练过程红队利用率比较高的漏洞进行总结汇总&#xff0c;具体的数据如下所示&#xff1a; ●远程代码执行漏洞 漏洞数量&#xff1a;6个 涉及厂商&#xff1a;YzmCMS、畅捷通、pgAdmin、泛微、锐捷、奇安信、 ●…

如何通过自己编写Jmeter函数

在Jmeter的函数助手里&#xff0c;有很多内置的函数&#xff0c;比如Random、UUID、time等等。使用这些函数可以快速帮我们生成某些数据&#xff0c;进行一些逻辑处理。用起来非常的方便。 但是在实际接口测试过程中&#xff0c;有很多的需求&#xff0c;Jmeter内置的函数可能…

苹果不会等到明年才对 Siri 进行改进|TodayAI

据彭博社报道&#xff0c;今年苹果&#xff08;APPLE&#xff09;将推出一个更令人满意的 Siri。 当 iOS 18 今年秋季推出时&#xff0c;Siri 的功能不仅仅是让你的 iPhone 边缘显示彩虹光环。虽然苹果智能功能要到 2025 年才会向非测试版用户推出&#xff0c;但据报道&#x…

每天写java到期末考试(6.19)--1.百元买百鸡

好久没有写了&#xff0c;现在赶快先复习复习&#xff0c;哈哈&#xff0c;加油&#xff01; 收获&#xff1a;写了好久&#xff0c;才写好这一个问题&#xff0c;提示自己不要好高骛远&#xff0c;前期先踏踏实实写好每一个代码&#xff1b; 被困住原因 取余%与整除/区别 pa…