Java多线程常见的10个经典面试题及答案整理

Java面试 潘老师 3个月前 (02-12) 56 ℃ (0) 扫码查看

Java程序员在出去找工作面试时基本都会被面试官问到关于多线程编程方面的知识点。因此潘老师给大家总结了面试官几乎必问的10个Java多线程常见面试题,非常经典,另外还附上了整理好的答案,耐心看完最好在理解的基础上背上,定能助你Java面试一臂之力。

第1题:线程和进程的基本概念、线程的基本状态以及状态之间转换(线程的生命周期)?

答案:
1)概念:进程是程序的一次执行过程,是系统运行程序的基本单位,进程是动态的。而线程与进程相似,但线程是一个比进程更小的执行单位。一个线程是进程的一个顺序执行流程。一个进程中的全部线程共享同一个堆空间。线程本身有一个供程序执行时的栈,一个进程中可以包含多个线程。
2)线程的基本状态:新建、就绪、运行状态、阻塞状态、死亡状态
新建状态:利用NEW运算创建了线程对象,此时线程状态为新建状态,调用了新建状态线程的start()方法,将线程提交给操作系统,准备执行,线程将进入到就绪状态。
就绪状态:由操作系统调度的一个线程,没有被系统分配到处理器上执行,一旦处理器有空闲,操作系统会将它放入处理器中执行,此时线程从就绪状态切换到运行时状态。
运行状态:线程正在运行的过程中,碰到调用Sleep()方法,或者等待IO完成,或等待其他同步方法完成时,线程将会从运行状态,进入到阻塞状态。
死亡状态:线程一旦脱离阻塞状态时,将重新回到就绪状态,重新向下执行,最终进入到死亡状态。一旦线程对象是死亡状态,就只能被GC回收,不能再被调用。
具体的可以看下图:

第2题:有哪几种创建线程的方式?

答案:
一般常用的有4种,分别如下:
  • 1)继承Thread类,重写run方法。
  • 2)实现Runnable接口,并重写里面的run方法。
  • 3)实现Callable接口,重写call()方法。
  • 4)使用Executors等创建线程池的方式创建。

第3题:Java代码如何保证多线程安全运行?

答案:
  • 1)使用安全类,比如 Java. util. concurrent(juc包) 下的原子类。
  • 2)使用同步锁 synchronized。
  • 3)使用手动锁 Lock。

第4题:同样是锁,synchronized 和 Lock 有什么区别?

答案:
1)首先synchronized是java内置关键字,在jvm层面,Lock是个java类;
2)synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
3)synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
4)用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
5)synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)
6)Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

第5题:启动线程调用start()方法还是run()方法?这两个方法有什么区别?

答案:
调用start()方法。区别如下:
调用start方法方可启动线程,真正实现了多线程,此时线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就自动执行run()方法;而run方法只是thread的一个普通方法调用还是在当前线程里执行,并没有增加线程的数量。

第6题:Java代码有哪几种常用方式解决生产者—消费者问题?

答案:
常用有3种方法解决生产者—消费者问题,如下:
  • synchronized版本
  • lock版实现,使用了condition做线程之间的同步。
  • BlockingQueue版实现

第7题:为什么要用线程池?线程池有哪几种创建方式?

答案:
为了减少创建和销毁线程的次数,让每个线程可以多次使用,可根据系统情况调整执行的线程数量,防止消耗过多内存,所以我们要使用线程池。线程池有如下几种创建方式:
1)Java通过Executors为我们提供了五种线程池的创建方式:
  • newCachedThreadPool:创建一个可缓存线程池
  • newCachedThreadPool:创建一个可缓存线程池
  • newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
  • newSingleThreadExecutor:创建一个单线程化的线程池
  • newWorkStealingPool(int parallelism):这是一个经常被人忽略的线程池,Java 8 才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序;

2)使用ThreadPoolExecutor()创建,这是最原始的线程池创建方式。

有兴趣的同学也可以看下Java8常见的面试题哦,关于线程池创建方式详细可参考:

Java创建线程池的几种方式具体实现

在讲解Java创建线程池的几种方式之前,潘老师先带大家了解一些关于线程池的概念和原理。 一、Java线程池是什 […]

第8题:ThreadPoolExecutor线程池类有几大参数?分别有什么作用?

答案:
ThreadPoolExecutor线程池类有7大参数,分别作用如下图:

第9题:stop方法终止线程为什么不安全?该怎么做?

答案:
1)线程中stop()方法作为一种粗暴的线程终止行为,在线程终止之前没有对其做任何的清除操作,因此具有固有的不安全性。它会释放已经锁定的所有监视资源,如果当前任何一个受监视资源保护的对象处于一个不一致的状态(执行了一部分),其他线程线程将会获取到修改了的部分值,这个时候就可能导致程序执行结果的不确定性,并且这种问题很难被定位。

2)在java中有以下2种正确方法可以终止正在运行的线程:

  • 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
  • 使用interrupt方法中断线程。

第10题:什么是死锁?怎么防止多线程发生死锁?

答案:
1)当线程 A 持有独占锁a,并尝试去获取独占锁 b 的同时,线程 B 持有独占锁 b,并尝试获取独占锁 a 的情况下,就会发生 AB 两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁。

2:)防止死锁方法:

  • 尽量使用 tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock、ReentrantReadWriteLock),设置超时时间,超时可以退出防止死锁。
  • 尽量使用 Java. util. concurrent 并发类代替自己手写锁。
  • 尽量降低锁的使用粒度,尽量不要几个功能用同一把锁。
  • 尽量减少同步的代码块。

总结

以上就是Java多线程常见的10个经典面试题和答案整理,你学会了吗?


版权声明:本站所有文章,如无特殊说明,均为本站原创。转载请务必注明文章来源,谢谢支持。
本文链接:https://www.panziye.com/javainterview/4323.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】