前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java并发基础面试题

Java并发基础面试题

原创
作者头像
Mark Sun
发布2023-01-29 23:04:37
3751
发布2023-01-29 23:04:37
举报

背景

本文涉及的六个问题,全部出自于Java小面的小朋友在大厂面试,所遇到问题。

问题本身不难,都是些基础的概念,这些问题的价值在于每一个问题背后都可以挖出很多要点。

这些问题相当于是一个垫脚石,基本如果这些问题都回答不好,那么问深层次八股文的机会都不会有,面试必挂。

所以大家请耐心看完,已经会的就当是温故知新了,当然说的有错或者纰漏也欢迎评论指正。

一、并发基础干货,非常干

1-请你说一说什么是线程和进程?

  • 区别

进程:有独立内存空间,每个进程中的数据空间都是独立的。

线程:多线程之间堆空间与方法区是共享的,但每个线程的栈空间、程序计数器是独立的,线程消耗的资源比进程小的多。

  • 关系

进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡过程。

一个进程可以有一个或者多个线程组成;线程是是进程中的一个执行单元,负责当前进程中任务的执行。

  • 线程的上下文切换是什么?

线程任务状态的保存及再加载的过程就叫做上下文切换。

  • 线程的并发与并行有啥区别?

并发(Concurrent):同一时间段内,多个任务都会被执行到 ,但不是在单位时间内同时执行。

并行(Parallel):单位时间内多个任务同时执行,并行上限取决于CPU核数。

2-使用多线程会带来什么问题?

  • 详细说说线程安全问题

线程安全问题出现在对同一块内存地址值的访问,如果这块内存地址值永远都不会改变,那么就不会出现线程安全问题。相反这个值,如果会被改变,那么多个线程就要考虑一个问题,大家由于上下文切换的缘故,在轮到其中一个线程访问该值的时候,是否读到的值和其他线程是同一个,线程安全问题由此产生。

  • 原子性、有序性和可见性深入的谈一下

➢ 原子性:指一组操作是一个完整的个体,要不都执行,要不不执行;

➢ 有序性:写程序是按照一定顺序,但程序在执行过程中由于指令重排,执行顺序会被调整;

➢ 可见性:仅在多线程有读写的情况需要考虑,一个线程修改内存中某一个值时,需要保证其他线程能读到修改的值,而不是原值。

3-什么是死锁?如何排查死锁?

  • 排查过程最好详细说明,最少说一种排查方案,越多越好

出现死锁,使用Arthas连接,对应JVM实例,thread -b命令一键式检测死锁。

当然这边还能提一嘴,JVM自带的jstack命令。

4-说一说JMM与happens-before?

这道题坑是比较大的,首先一点对于刚接触Java的程序员来说,可能还有一个JVM内存模型八股文被广泛传颂,但是注意一点你说了它,那就尬住,

  • 什么是 JMM 内存模型?

JMM定义是Java语言与操作系统内存是如何交互;而JVM内存模型,指的是JVM实例运行时内存区域是如何划分的。

其实这点你能明确讲到,其他的深入再说说,不同系统有不同的实现细节等等,这些就都是锦上添花了,能衍生自己擅长的那就是最好的。

  • 什么是 happens-before 规则?

涉及的规则不止我下面罗列的,但是以下四条是我认为比较关键的点,且大家的说法也基本都是如出一辙,这里我就拿相关资料上所描述的内容,

➢ 程序次序规则:在一个线程中,按照代码的顺序,前面的操作happens-before于后面的任意操作

➢ Volatile变量规则:对一个volatile修饰的变量的写, happens-before与任意后续对这个变量的读

➢ 传递性:如果A happens-before B,并且B happens-before C,则A happens-before C

➢ 锁定规则:对一个锁的解锁, happens-before与随后对这个锁的加锁

如果能能再展开讲讲线程启动规则、线程终结规则、线程中断规则、对象终结原则,那很不错。

5-为什么使用线程池?如何创建线程池?

  • 手动创建和自动创建线程池都需要介绍

手动创建,使用ThreadPoolExecutor的构造函数,配置线程池参数。

自动创建,使用Executors提供的几个类方法直接创建。

  • 最好能介绍一下线程池的实现原理

由于频繁创建线程是会有额外的时间开销的,因此池化的理念同样被JDK中线程池引入并实现。

这里重点关注两个参数需要拿出来讲讲,corePoolSize、maxPoolSize,参数的关系如下所述,

➢线程数 < corePoolSize,就算有工作线程处于空闲状态,仍旧会创建新线程执行task。

➢线程数 >= corePoolSize,但 < maxPoolSize,将任务放入task队列中。

➢队列已满,并且线程数 < maxPoolSize,那么创建新线程来执行task。

➢队列已满,并且线程数 >= maxPoolSize,则根据任务拒绝策略进行拒绝。

6-ThreadLocal中Map的key为什么要使用弱引用?

  • 为什么说不清理自定义的 ThreadLocal 变量会导致内存泄露呢?

相互之间的关系,这块最好能够手绘出来,这样既体现你对其的理解,一定程度上也能够体现你代码设计能力。

Thread Ref → Current Thread → ThreadLocalMap → Entry → Value

线程对象存活以上链路的引用关系就会一直存在,如果该线程执行耗时任务,线程一直存活,那么当GC进行可达性分析的时候,由于 Value 可达的,无法回收。如果业务逻辑已经完成处理,这时就不再需要这个 Value,但是由于其一直未被清理,此时也就发生了内存泄漏问题。

小结

本文属于对所提问题的要点阐述,如果你能在这些得分点的基础上回答的更加完善,面试在我这绝对是加分项,并且我相信大多数面试官也是如此。

另外,如果对并发编程或者面试,想要了解更多请持续关注微信公众号:Java面试教程,关注更多有用的面试要点与技巧。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 一、并发基础干货,非常干
    • 1-请你说一说什么是线程和进程?
      • 2-使用多线程会带来什么问题?
        • 3-什么是死锁?如何排查死锁?
          • 4-说一说JMM与happens-before?
            • 5-为什么使用线程池?如何创建线程池?
              • 6-ThreadLocal中Map的key为什么要使用弱引用?
                • 小结
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档