zoukankan      html  css  js  c++  java
  • 线程池经典问题整理

    线程池是一种多线程处理形式,它是Java开发面试中的必考知识点,尤其是在一些大厂的求职面试中,线程池是对求职者考核的重点。为了帮助大家可以更好地通过面试,本文特地为大家整理了线程池经典面试题并附上了答案,下面一起来尝试着做一做吧!

    1.什么是线程池

    java.util.concurrent.Executors提供了一个 java.util.concurrent.Executor接口的实现用于创建线程池

    多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。
    假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。

    如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。

    一个线程池包括以下四个基本组成部分:
    1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
    2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
    3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
    4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。

    线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
    线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一个例子:
    假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。

    2.使用线程池有哪些好处?

    降低资源消耗,通过重复利用已创建的线程,降低线程创建和销毁造成的消耗;提高响应速度,当任务到达时,任务可以不需要等到线程创建就能立即执行;增加线程的可管理型,线程是稀缺资源,使用线程池可以进行统一分配,调优和监控。
    阿里巴巴Java开发手册中有说明:

    3.概述一下线程池的核心属性

    (1)线程工厂:用于创建工作线程的工厂。

    (2)核心线程数:当线程池运行的线程少于 corePoolSize 时,将创建一个新线程来处理请求,即使其他工作线程处于空闲状态。

    (3)队列:用于保留任务并移交给工作线程的阻塞队列。

    (4)最大线程数:线程池允许开启的最大线程数。

    (5)拒绝策略:往线程池添加任务时,将在下面两种情况触发拒绝策略:一是线程池运行状态不是 RUNNING;二是线程池已经达到最大线程数,并且阻塞队列已满时。

    (6)保持存活时间:如果线程池当前线程数超过 corePoolSize,则多余的线程空闲时间超过 keepAliveTime 时会被终止。

    4.生产中为什么不用JDK自带的创建线程池的方法?

    5.在我们实际使用中,线程池的大小配置多少合适?

    要想合理的配置线程池大小,首先我们需要区分任务是计算密集型还是I/O密集型。对于计算密集型,设置 线程数 = CPU数 + 1,通常能实现最优的利用率。对于I/O密集型,网上常见的说法是设置 线程数 = CPU数 * 2 ,这个做法是可以的,但不是最优的。

    在我们日常的开发中,我们的任务几乎是离不开I/O的,常见的网络I/O(RPC调用)、磁盘I/O(数据库操作),并且I/O的等待时间通常会占整个任务处理时间的很大一部分,在这种情况下,开启更多的线程可以让 CPU 得到更充分的使用,一个较合理的计算公式如下:

    线程数 = CPU数 * CPU利用率 * (任务等待时间 / 任务计算时间 + 1)

    例如我们有个定时任务,部署在4核的服务器上,该任务有100ms在计算,900ms在I/O等待,则线程数约为:4 * 1 * (1 + 900 / 100) = 40个。当然,具体我们还要结合实际的使用场景来考虑。

    6.终止线程池有哪些方式?

    (1)shutdown:“温柔”的关闭线程池。不接受新任务,但是在关闭前会将之前提交的任务处理完毕。

    (2)shutdownNow:“粗暴”的关闭线程池,也就是直接关闭线程池,通过 Thread#interrupt() 方法终止所有线程,不会等待之前提交的任务执行完毕。但是会返回队列中未处理的任务。

    7.线程池拒绝策略有哪些?

    7.1 线程池的拒绝策略是什么

    等待队列也已经满了,再也塞不下新任务了。同时线程池中的max线程数也达到了,无法继续为新任务服务。这时候我们就需要拒绝策略机制合理的解决这个问题。

    7.2 JDK内置的拒绝策略

    7.2.1 AbortPolicy

    抛出RejectedExecutionException异常阻止系统正常运行。

    public class MyThreadPoolDemo {
        public static void main(String[] args) {
            ExecutorService threadPool = new ThreadPoolExecutor(
                    2,
                    5,
                    1L,
                    TimeUnit.SECONDS,
                    new LinkedBlockingQueue<>(3),
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.DiscardPolicy()
            );
            try{
                for (int i = 1; i <=10 ; i++) {
                    threadPool.execute(()->{
                        System.out.println(Thread.currentThread().getName() + "	办理业务");
                    });
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                threadPool.shutdown();
            }
        }
    }
    

    打印结果:

    惨嚎

    艾欧尼亚,昂扬不灭,为了更美好的明天而战(#^.^#)
  • 相关阅读:
    windows安装python2.7后的注册(registry)问题
    用python解析pdf中的文本与表格【pdfplumber的安装与使用】
    python pdfplumber用于pdf表格提取
    python xlsxwriter写excel并操作各种格式属性
    ShellExecute, WinExec, CreateProcess区别
    Python调用Windows外部程序
    pynput使用简单说明
    有关/proc/uptime这个文件里两个参数所代表的意义
    Beyond Compare 4 提示错误“这个授权密钥已被吊销”的解决办法
    Android: adb push apk 到 system/app 目录时报“remote Read-only file system”
  • 原文地址:https://www.cnblogs.com/lovelywcc/p/14445969.html
Copyright © 2011-2022 走看看