Java 面试知识点【背诵版 240题 约7w字】 (22)

③ join 方法用于等待其他线程运行终止,如果当前线程调用了另一个线程的 join 方法,则当前线程进入阻塞状态,当另一个线程结束时当前线程才能从阻塞状态转为就绪态,等待获取CPU时间片。底层使用的是wait,也会释放锁。

Q4:什么是守护线程?

守护线程是一种支持型线程,可以通过 setDaemon(true) 将线程设置为守护线程,但必须在线程启动前设置。

守护线程被用于完成支持性工作,但在 JVM 退出时守护线程中的 finally 块不一定执行,因为 JVM 中没有非守护线程时需要立即退出,所有守护线程都将立即终止,不能靠在守护线程使用 finally 确保关闭资源。

Q5:线程通信的方式有哪些?

命令式编程中线程的通信机制有两种,共享内存和消息传递。在共享内存的并发模型里线程间共享程序的公共状态,通过写-读内存中的公共状态进行隐式通信。在消息传递的并发模型里线程间没有公共状态,必须通过发送消息来显式通信。Java 并发采用共享内存模型,线程之间的通信总是隐式进行,整个通信过程对程序员完全透明。

volatile 告知程序任何对变量的读需要从主内存中获取,写必须同步刷新回主内存,保证所有线程对变量访问的可见性。

synchronized 确保多个线程在同一时刻只能有一个处于方法或同步块中,保证线程对变量访问的原子性、可见性和有序性。

等待通知机制指一个线程 A 调用了对象的 wait 方法进入等待状态,另一线程 B 调用了对象的 notify/notifyAll 方法,线程 A 收到通知后结束阻塞并执行后序操作。对象上的 wait 和 notify/notifyAll 如同开关信号,完成等待方和通知方的交互。

如果一个线程执行了某个线程的 join 方法,这个线程就会阻塞等待执行了 join 方法的线程终止,这里涉及等待/通知机制。join 底层通过 wait 实现,线程终止时会调用自身的 notifyAll 方法,通知所有等待在该线程对象上的线程。

管道 IO 流用于线程间数据传输,媒介为内存。PipedOutputStream 和 PipedWriter 是输出流,相当于生产者,PipedInputStream 和 PipedReader 是输入流,相当于消费者。管道流使用一个默认大小为 1KB 的循环缓冲数组。输入流从缓冲数组读数据,输出流往缓冲数组中写数据。当数组已满时,输出流所在线程阻塞;当数组首次为空时,输入流所在线程阻塞。

ThreadLocal 是线程共享变量,但它可以为每个线程创建单独的副本,副本值是线程私有的,互相之间不影响。

Q6:线程池有什么好处?

降低资源消耗,复用已创建的线程,降低开销、控制最大并发数。

隔离线程环境,可以配置独立线程池,将较慢的线程与较快的隔离开,避免相互影响。

实现任务线程队列缓冲策略和拒绝机制。

实现某些与时间相关的功能,如定时执行、周期执行等。

Q7:线程池处理任务的流程?

① 核心线程池未满,创建一个新的线程执行任务,此时 workCount < corePoolSize。

② 如果核心线程池已满,工作队列未满,将线程存储在工作队列,此时 workCount >= corePoolSize。

③ 如果工作队列已满,线程数小于最大线程数就创建一个新线程处理任务,此时 workCount < maximumPoolSize,这一步也需要获取全局锁。

④ 如果超过大小线程数,按照拒绝策略来处理任务,此时 workCount > maximumPoolSize。

线程池创建线程时,会将线程封装成工作线程 Worker,Worker 在执行完任务后还会循环获取工作队列中的任务来执行。

Q8:有哪些创建线程池的方法?

可以通过 Executors 的静态工厂方法创建线程池:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwpgxs.html