面试题(二)

目录

21.JVM中哪些是线程共享区

22.你们项⽬如何排查JVM问题

23.⼀个对象从加载到JVM,再到被GC清除,都经历了什么过程?

24.怎么确定⼀个对象到底是不是垃圾?

25.GC Root 是什么?

26.JVM有哪些垃圾回收算法?

27.什么是STW?

28.JVM参数有哪些?

29.说说对线程安全的理解

30.对守护线程的理解

31.ThreadLocal的底层原理

 32.并发、并⾏、串⾏之间的区别

33.Java死锁如何避免?

34.线程池的底层⼯作原理

35.线程池为什么是先添加列队⽽不是先创建最⼤线程?

 36.ReentrantLock中的公平锁和⾮公平锁的底层实现

37.ReentrantLock中tryLock()和lock()⽅法的区别

38.CountDownLatch和Semaphore的区别和底层原理

39.Sychronized的偏向锁、轻量级锁、重量级锁

40.Sychronized和ReentrantLock的区别


21.JVM中哪些是线程共享区

JVM中线程共享区有: 堆和方法区

JVM中线程独有的是:  栈,本地方法栈,程序计数器

22.你们项⽬如何排查JVM问题

对于还在正常运⾏的系统:
1. 可以使⽤jmap来查看JVM中各个区域的使⽤情况
2. 可以通过jstack来查看线程的运⾏情况,⽐如哪些线程阻塞、是否出现了死锁
3. 可以通过jstat命令来查看垃圾回收的情况,特别是fullgc,如果发现fullgc⽐较频繁,那么就得进⾏ 调优了
4. 通过各个命令的结果,或者 jvisualvm等⼯具来进⾏分析
5. ⾸先,初步猜测频繁发送fullgc的原因,如果频繁发⽣fullgc但是⼜⼀直没有出现内存溢出,那么表 示fullgc实际上是回收了很多对象了,所以这些对象最好能在younggc过程中就直接回收掉,避免这 些对象进⼊到⽼年代,对于这种情况,就要考虑这些存活时间不⻓的对象是不是⽐较⼤,导致年轻 代放不下,直接进⼊到了⽼年代,尝试加⼤年轻代的⼤⼩,如果改完之后,fullgc减少,则证明修改有效
6. 同时,还可以找到占⽤CPU最多的线程,定位到具体的⽅法,优化这个⽅法的执⾏,看是否能避免 某些对象的创建,从⽽节省内存
对于已经发⽣了OOM的系统:
1. ⼀般⽣产系统中都会设置当系统发⽣了OOM时,⽣成当时的dump⽂件( -
XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/base
2. 我们可以利⽤jsisualvm等⼯具来分析dump⽂件
3. 根据dump⽂件找到异常的实例对象,和异常的线程(占⽤CPU⾼),定位到具体的代码
4. 然后再进⾏详细的分析和调试
总之,调优不是⼀蹴⽽就的,需要分析、推理、实践、总结、再分析,最终定位到具体的问题

 

23.⼀个对象从加载到JVM,再到被GC清除,都经历了什么过程?

  • 首先把字节码文件内容加载到方法区
  • 再根据类信息在堆创建对象
  • 对象首先分配在堆中的年轻代的伊甸园区,经过一次轻GC之后,如果对象存在就进入幸存一区,
  • 在之后经过多次轻GC过后,如果对象一直存活,这个对象就会在幸存一区和幸存二区来回from to,
  • 每一次from to 移动 年龄就会增长1岁
  • 当年龄大于15岁,如果这个对象还存活,就会进入老年区
  • 在老年区时,经过full GC ,如果被标记为垃圾对象,就会被GC线程清除

24.怎么确定⼀个对象到底是不是垃圾?

引用计数器: 这种方式就是给堆内存中的对象进行计数,当计数为0时,就会被认为是垃圾对象。这是早起JDK的方式,无法解决循环引用问题。

可达性分析:从一个根对象 (GC root)向下寻找,找到的就不是垃圾对象,未找到的就是垃圾对象。

25.GC Root 是什么?

GC Root 就是根对象,栈中的局部变量表,方法区中的静态变量,正在运行的线程,本地方法栈中的变量都可以是GCRoot。

26.JVM有哪些垃圾回收算法?

1. 标记清除算法:
        a. 标记阶段:把垃圾内存标记出来
        b. 清除阶段:直接将垃圾内存回收。
        c. 这种算法是⽐较简单的,但是有个很严重的问题,就是会产⽣⼤量的内存碎⽚。
2. 复制算法:为了解决标记清除算法的内存碎⽚问题,就产⽣了复制算法。复制算法将内存分为⼤⼩ 相等的两半,每次只使⽤其中⼀半。垃圾回收时,将当前这⼀块的存活对象全部拷⻉到另⼀半,然 后当前这⼀半内存就可以直接清除。这种算法没有内存碎⽚,但是他的问题就在于浪费空间。⽽ 且,他的效率跟存活对象的个数有关。
3. 标记压缩算法:为了解决复制算法的缺陷,就提出了标记压缩算法。这种算法在标记阶段跟标记清 除算法是⼀样的,但是在完成标记之后,不是直接清理垃圾内存,⽽是将存活对象往⼀端移动,然 后将边界以外的所有内存直接清除。

27.什么是STW?

STW(Stop The World) :在执行垃圾回收时,将JVM冻结的一种状。发生STW时,停止一切Java线交互,本地方法native可以执行,但是不能与JVM进行交互。各种算法的优化就是减少STW。

28.JVM参数有哪些?

JVM参数⼤致可以分为三类:
1. 标准 指令: -开头,这些是所有的HotSpot都⽀持的参数。可以⽤java -help 打印出来。
2. ⾮标准指令: -X开头,这些指令通常是跟特定的HotSpot版本对应的。可以⽤java -X 打印出来。
3. 不稳定参数: -XX 开头,这⼀类参数是跟特定HotSpot版本对应的,并且变化⾮常⼤

29.说说对线程安全的理解

线程安全指的是,我们写的某段代码,在多个线程同时执⾏这段代码时,不会产⽣混乱,依然能够得到 正常的结果,⽐如i++,i初始化值为0,那么两个线程来同时执⾏这⾏代码,如果代码是线程安全的,那么最终的结果应该就是⼀个线程的结果为1,⼀个线程的结果为2,如果出现了两个线程的结果都为1,则 表示这段代码是线程不安全的。
所以线程安全,主要指的是⼀段代码在多个线程同时执⾏的情况下,能否得到正确的结果。

30.对守护线程的理解

线程分为⽤户线程和守护线程,⽤户线程就是普通线程,守护线程就是JVM的后台线程,⽐如垃圾回收 线程就是⼀个守护线程,守护线程会在其他普通线程都停⽌运⾏之后⾃动关闭。我们可以通过设置 thread.setDaemon(true)来把⼀个线程设置为守护线程

31.ThreadLocal的底层原理

1. ThreadLocal是Java中所提供的线程本地存储机制,可以利⽤该机制将数据 缓存在某个线程内部 , 该线程可以在任意时刻、任意⽅法中获取缓存的数据
2. ThreadLocal底层是通过 ThreadLocalMap来实现的,每个Thread对象(注意不是ThreadLocal对
象)中都存在⼀个ThreadLocalMap,Map的key为ThreadLocal对象,Map的value为需要缓存的
3. 如果在线程池中使⽤ThreadLocal会造成内存泄漏,因为当ThreadLocal对象使⽤完之后,应该要把 设置的key,value,也就是Entry对象进⾏回收,但线程池中的线程不会回收,⽽线程对象是通过强 引⽤指向ThreadLocalMap,ThreadLocalMap也是通过强引⽤指向Entry对象,线程不被回收, Entry对象也就不会被回收,从⽽出现内存泄漏,解决办法是,在使⽤了ThreadLocal对象之后,⼿ 动调⽤ThreadLocal的remove⽅法,⼿动清楚Entry对象
4. ThreadLocal经典的应⽤场景就是连接管理(⼀个线程持有⼀个连接,该连接对象可以在不同的⽅ 法之间进⾏传递,线程之间不共享同⼀个连接)

 32.并发、并⾏、串⾏之间的区别

1. 串⾏:⼀个任务执⾏完,才能执⾏下⼀个任务
2. 并⾏( Parallelism ):两个任务同时执⾏
3. 并发( Concurrency ):两个任务整体看上去是同时执⾏,在底层,两个任务被拆成了很多份,然后⼀个⼀个执⾏,站在更⾼的⻆度看来两个任务是同时在执⾏的

33.Java死锁如何避免?

造成死锁的⼏个原因:
1. ⼀个资源每次只能被⼀个线程使⽤
2. ⼀个线程在阻塞等待某个资源时,不释放已占有资源
3. ⼀个线程已经获得的资源,在未使⽤完之前,不能被强⾏剥夺
4. 若⼲线程形成头尾相接的循环等待资源关系
这是造成死锁必须要达到的4个条件,如果要避免死锁,只需要不满⾜其中某⼀个条件即可。⽽其中前3 个条件是作为锁要符合的条件,所以要避免死锁就需要打破第4个条件,不出现循环等待锁的关系。
在开发过程中:
1. 要注意加锁顺序,保证每个线程按同样的顺序进⾏加锁
2. 要注意加锁时限,可以针对所设置⼀个超时时间
3. 要注意死锁检查,这是⼀种预防机制,确保在第⼀时间发现死锁并进⾏解决

34.线程池的底层⼯作原理

线程池内部是通过队列+线程实现的,当我们利⽤线程池执⾏任务时:
1. 如果此时线程池中的线程数量⼩于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建 新的线程来处理被添加的任务。
2. 如果此时线程池中的线程数量等于corePoolSize,但是缓冲队列workQueue未满,那么任务被放⼊ 缓冲队列。
3. 如果此时线程池中的线程数量⼤于等于corePoolSize,缓冲队列workQueue满,并且线程池中的数 量⼩于maximumPoolSize,建新的线程来处理被添加的任务。
4. 如果此时线程池中的线程数量⼤于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等 于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。
5. 当线程池中的线程数量⼤于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被 终⽌。这样,线程池可以动态的调整池中的线程数

35.线程池为什么是先添加列队⽽不是先创建最⼤线程?

        当线程池中的核⼼线程都在忙时,如果继续往线程池中添加任务,那么任务会先放⼊队列,队列满了之 后,才会新开线程。这就相当于,⼀个公司本来有10个程序员,本来这10个程序员能正常的处理各种需 求,但是随着公司的发展,需求在慢慢的增加,但是⼀开始这些需求只会增加在待开发列表中,然后这 10个程序员加班加点的从待开发列表中获取需求并进⾏处理,但是某⼀天待开发列表满了,公司发现现有的10个程序员是真的处理不过来了,所以就开始新招员⼯了。

 36.ReentrantLock中的公平锁和⾮公平锁的底层实现

        ⾸先不管是公平锁和⾮公平锁,它们的底层实现都会使⽤AQS来进⾏排队,它们的区别在于:线程在使 ⽤lock()⽅法加锁时,如果是公平锁,会先检查AQS队列中是否存在线程在排队,如果有线程在排队, 则当前线程也进⾏排队,如果是⾮公平锁,则不会去检查是否有线程在排队,⽽是直接竞争锁。 不管是公平锁还是⾮公平锁,⼀旦没竞争到锁,都会进⾏排队,当锁释放时,都是唤醒排在最前⾯的线 程,所以⾮公平锁只是体现在了线程加锁阶段,⽽没有体现在线程被唤醒阶段。
另外,ReentrantLock是可重⼊锁,不管是公平锁还是⾮公平锁都是可重⼊的

37.ReentrantLock中tryLock()和lock()⽅法的区别

1. tryLock()表示尝试加锁,可能加到,也可能加不到,该⽅法不会阻塞线程,如果加到锁则返回
true,没有加到则返回false
2. lock()表示阻塞加锁,线程会阻塞直到加到锁,⽅法也没有返回值

38.CountDownLatch和Semaphore的区别和底层原理

  • CountDownLatch表示计数器,可以给CountDownLatch设置⼀个数字,⼀个线程调⽤
  • CountDownLatch的await()将会阻塞,其他线程可以调⽤CountDownLatch的countDown()⽅法来对 CountDownLatch中的数字减⼀,当数字被减成0后,所有await的线程都将被唤醒。
  • 对应的底层原理就是,调⽤await()⽅法的线程会利⽤AQS排队,⼀旦数字被减为0,则会将AQS中 排队的线程依次唤醒。
  • Semaphore表示信号量,可以设置许可的个数,表示同时允许最多多少个线程使⽤该信号量,通 过acquire()来获取许可,如果没有许可可⽤则线程阻塞,并通过AQS来排队,可以通过release()
  • ReentrantLock中tryLock()和lock()⽅法的区别
  • CountDownLatch和Semaphore的区别和底层原理⽅法来释放许可,当某个线程释放了某个许可后,会从AQS中正在排队的第⼀个线程开始依次唤 醒,直到没有空闲许可。

39.Sychronized的偏向锁、轻量级锁、重量级锁

1. 偏向锁:在锁对象的对象头中记录⼀下当前获取到该锁的线程ID,该线程下次如果⼜来获取该锁就 可以直接获取到了
2. 轻量级锁:由偏向锁升级⽽来,当⼀个线程获取到锁后,此时这把锁是偏向锁,此时如果有第⼆个 线程来竞争锁,偏向锁就会升级为轻量级锁,之所以叫轻量级锁,是为了和重量级锁区分开来,轻 量级锁底层是通过⾃旋来实现的,并不会阻塞线程
3. 如果⾃旋次数过多仍然没有获取到锁,则会升级为重量级锁,重量级锁会导致线程阻塞
4. ⾃旋锁:⾃旋锁就是线程在获取锁的过程中,不会去阻塞线程,也就⽆所谓唤醒线程,阻塞和唤醒 这两个步骤都是需要操作系统去进⾏的,⽐较消耗时间,⾃旋锁是线程通过CAS获取预期的⼀个标 记,如果没有获取到,则继续循环获取,如果获取到了则表示获取到了锁,这个过程线程⼀直在运 ⾏中,相对⽽⾔没有使⽤太多的操作系统资源,⽐较轻量。

40.Sychronized和ReentrantLock的区别

1. sychronized是⼀个关键字,ReentrantLock是⼀个类
2. sychronized会⾃动的加锁与释放锁,ReentrantLock需要程序员⼿动加锁与释放锁
3. sychronized的底层是JVM层⾯的锁,ReentrantLock是API层⾯的锁
4. sychronized是⾮公平锁,ReentrantLock可以选择公平锁或⾮公平锁
5. sychronized锁的是对象,锁信息保存在对象头中,ReentrantLock通过代码中int类型的state标识 来标识锁的状态
6. sychronized底层有⼀个锁升级的过程

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RabbitMQ 01

01.定义 02.功能

18个西语常用前置词用法大全,柯桥西班牙语培训

西语词类有九种:名词、冠词、形容词、代词、动词、副词、感叹词、前置词和连接词。 其中,“前置词”也就是我们俗称的“介词”,它是一种不变词类,本身没有独立的词汇意义,在句中与名词、形容词、动词等连用&#xff0…

BM43 包含min函数的栈(Stack)

import java.util.*; import java.util.Stack;public class Solution {Stack<Integer> s1 new Stack<Integer>();//存最小的元素Stack<Integer> s2 new Stack<Integer>();public void push(int node) {s1.push(node);if(s2.isEmpty() || s2.peek() &…

2024-03-23 问AI: 介绍一下深度学习中的ReLU函数

文心一言 ReLU&#xff08;Rectified Linear Unit&#xff09;函数是深度学习领域中常用的一种激活函数。它具有简单、计算高效且在某些情况下能有效缓解梯度消失问题等优点&#xff0c;因此在神经网络中得到了广泛的应用。 ReLU函数的定义非常简单&#xff0c;其数学表达式为…

Element Plus 基本使用

一、概述 1.1介绍 Element Plus 基本使用 element-ui 是基于vue 开发的一套ui组件库&#xff0c;提供丰富的网页开发组件&#xff0c;可用快速开发网站&#xff0c;降低前端开发成本版本 element目前有两个版本 element-ui&#xff1a;基于vue2element-plus: 基于vue3 官网地址…

2-dubbo源码 : 源码环境搭建

好的开始是成功的一半&#xff0c;阅读源码也是一样。 很多同学在下定决心阅读一个开源框架之后&#xff0c;就一头扎进去&#xff0c;迷失在代码“迷宫”中。此时&#xff0c;有同学意识到&#xff0c;需要一边 Debug 一边看&#xff1b;然后又有一批同学在搭建源码环境的时候…

鸿蒙一次开发,多端部署(十五)常见问题

如何查询设备类型 设备类型分为default&#xff08;默认设备&#xff09;、tablet、tv、wearable、2in1等&#xff0c;有多种查询设备类型的方式。 通过命令行的方式查询设备类型。 通过命令行查询指定系统参数&#xff08;const.product.devicetype&#xff09;进而确定设备…

Java基础-常用类

文章目录 1.Math类2.System类1.exit代码 结果2.arraycopy参数解释代码结果 3.currentTimeMillens代码结果 3.大数处理方案基本介绍BigInteger类介绍代码结果 BigDecimal类介绍代码结果 4.日期类对于IDEA类图中的属性![image-20240101190844530](https://img-blog.csdnimg.cn/im…

能降低嵌入式系统功耗的三个技术

为电池寿命设计嵌入式系统已经成为许多团队重要的设计考虑因素。优化电池寿命的能力有助于降低现场维护成本&#xff0c;并确保客户不需要不断更换或充电电池&#xff0c;从而获得良好的产品体验。 团队通常使用一些标准技术来提高电池寿命&#xff0c;例如将处理器置于低功耗…

RIPGeo代码理解(六)main.py(运行模型进行训练和测试)

​代码链接:RIPGeo代码实现 ├── preprocess.py # 预处理数据集并为模型运行执行IP聚类 ├── main.py # 运行模型进行训练和测试 ├── test.py #加载检查点,然后测试 一、导入各种模块和数据库 import torch.nnfrom lib.utils import * import argparse i…

162、应急响应——网站入侵篡改指南Webshell内存马查杀漏洞排查时间分析

文章目录 IIS&.NET—注入—基于时间配合日志分析Apache&PHP—漏洞—基于漏洞配合日志分析Tomcat&JSP—弱口令—基于后门配合日志分析查杀常规后门查杀内存马 需要了解&#xff1a; 异常检测、处置流程、分析报告等 网站被入侵会出现异常&#xff1a;流量异常、防护…

Git版本控制

这是两个学习Git推荐必看的文档&#xff0c;第一个链接是Git的官方权威文档&#xff0c;第二个链接是国内程序员在开发中&#xff0c;总结的Git快速入门教程&#xff0c;掌握这个&#xff0c;也足够应付在工作中的场景。 Git权威书籍《ProGit》中文版https://gitee.com/progit…

Web框架开发-Ajax

一、 Ajax准备知识:json 1、json(Javascript Obiect Notation,JS对象标记)是一种轻量级的数据交换格式 1 2 它基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。 简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。…

从redis安装到使用再到源码和底层原理分析指南【万字长文】

Redis 安装redis-cli记录单线程多路IO复用Redis字符串Redis列表 事务Redis悲观锁和乐观锁AOF主从集群概念slots Redis应用问题解决缓存穿透缓存击穿缓存雪崩分布式锁 重启和停止redis server配置登陆密码 配置外网访问Redis源码学习server守护进程实现server处理信号redis obje…

每日一题——LeetCode2549.统计桌面上的不同数字

方法一 模拟 维护一个数组arr&#xff0c;初始值为n,每次循环将arr[i] % j(1<j<n) 如果结果为1则将j加入&#xff0c; 最后将arr转为Set集合去重&#xff0c;Set的长度就是答案 var distinctIntegers function(n) {let arr[]arr.push(n)for(let i0;i<arr.length;i…

JAVA毕业设计131—基于Java+Springboot+Vue的餐厅点餐系统(源代码+数据库+4000字文档)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootVue的餐厅点餐系统(源代码数据库4000字文档)131 一、系统介绍 本项目前后端分离&#xff0c;分为管理员、用户两种角色 1、用户&#xff1a; 注册、登录、点餐…

SpringBoot2.x 整合SpringDocJavadocknife4j实现无注解零入侵式接口文档

说明 基于 javadoc 无注解零入侵生成规范的 openapi 结构体。 文档工具使用 由于框架采用 openapi 行业规范 故市面上大部分的框架均支持 可自行选择 例如: apifox apipost postman torna knife4j 等 根据对应工具的文档接入即可 Swagger升级SpringDoc指南 常见功能如下 其他…

RHEL9部署Docker环境

华子目录 Docker引擎架构docker引擎架构示意图执行过程示例 RHEL9上安装Docker1.系统要求2.安装yum-utils工具包3.yum安装docker-ce4.配置docker镜像加速docker拉取镜像的过程配置阿里云镜像仓库重新加载守护进程重启Docker服务 5.拉取并运行hello-world镜像6.测试是否安装成功…

【Godot4.2】基础知识 - Godot中的2D向量

概述 在Godot中&#xff0c;乃至一切游戏编程中&#xff0c;你应该都躲不开向量。这是每一个初学者都应该知道和掌握的内容&#xff0c;否则你将很难理解和实现某些其实原理非常简单的东西。 估计很多刚入坑Godot的小伙伴和我一样&#xff0c;不一定是计算机专业或编程相关专…

ROS机器人入门第二课:ROS集成开发环境搭建

文章目录 ROS机器人入门第二课&#xff1a;ROS集成开发环境搭建一、安装终端&#xff08;一&#xff09;安装Terminator&#xff08;二&#xff09;添加到收藏夹&#xff08;三&#xff09;Terminator 常用快捷键第一部份&#xff1a;关于在同一个标签内的操作第二部份&#xf…