zoukankan      html  css  js  c++  java
  • java面试一日一题:java线程池

    问题:请讲下java中的线程池

    分析:在面试中经常问到线程池的问题,要掌握其基本概念,使用方法,注意事项等,引申下tomcat中默认的线程数是多少

    回答要点:

    主要从以下几点去考虑,

    1、为什么要使用线程池

    2、线程池的基本参数

    3、为什么不使用java提供的线程池,而是使用自己创建

    4、如何设置线程数大小;

    5、线程池在tomcat中的使用;

    为什么要使用线程池

    在日常的开发过程中,经常要用到多线程,那么为什么不直接新建一个线程,而是选择使用线程池那,因为线程的创建要消耗系统资源,占用CPU的时间,所以考虑使用线程池;

    线程池的基本参数

    Java提供了线程池类ThreadPoolExecutor,该类是线程池的基类,有以下参数

    corePoolSize   核心线程数

    maximumPoolSize  最大线程数

    keepAliveTime  线程数超过核心线程数后,多余的线程的空闲时间

    unit  上面的参数的单位

    workQueue  阻塞队列

    threadFactory  创建线程的工厂

    handler  拒绝策略

    一个任务被提交到线程池的过程:

    从上面的流程图中可以引申出以下几个问题,核心线程数要怎么设置;阻塞队列有几种;拒绝策略有几种;

    先看阻塞队列及决策策略

    阻塞队列

    常用的阻塞队列有ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、priorityBlockingQueue

    ArrayBlockingQueue  底层使用数组+ReeTrantLock实现,既然是数组实现那么必然就要指定数组的长度

    LinkedBlockingQueue  使用单链表实现,最大长度为Integer.MAX_VALUE

    SynchronousQueue  要将任务放入SynchronousQueue中必须有一个线程在等待消费该任务,如果没有线程在等待,那么线程池中线程数小于最大线程数就会创建一个线程,否则会执行拒绝策略

    PriorityBlockingQueue  具有优先级的阻塞队列

    拒绝策略

    ThreadPoolExecutor实现了4中拒绝策略,CallerRunsPolicy、AbortPolicy、DiscardPolicy、DiscardOldestPolicy

    CallerRunsPolicy  调用者来执行该任务;

    AbortPolicy  抛出异常,开发者可以捕获该异常,默认的策略;

    DiscardPolicy  直接丢弃,什么也不做;

    DiscardOldestPolicy  丢弃队列中最老的任务,就是最先入队的任务,也即将要被执行的任务;

    java提供的线程池

    Java的Exectors类提供了一些线程池的方法供开发者来用,但是最好不用Java提供的,下面看有哪些以及为什么不建议使用

    newFixedThreadPool()  固定线程数的线程池,核心线程数=最大线程数,使用LinkedBlockingQueue,拒绝策略是默认的AbortPolicy;适用于为了满足资源管理的要求,而限制线程数量,适用于负载较重的机器

    newSingleThreadExecutor()  只有一个线程的线程池,核心线程数=最大线程数=1,使用LinkedBlockingQueue,拒绝策略是默认的AbortPolicy;适用于顺序执行各个任务的场景

    newCachedThreadPool()  按需创建新的线程池,核心线程数=0,最大线程数为Integer.MAX_VALUE,阻塞队列为SynchronousQueue,拒绝策略是默认的AbortPolicy,线程池可以无限扩展,当任务多时创建许多线程,任务少时,自动清空线程;适应于执行短期异步任务,或者负载较轻的机器

    newScheduledThreadPool()  创建一个延时或定时的线程池,最大线程数为Integer.MAX_VALUE,阻塞队列为DelayedWorkQueue

    如何设置线程池中线程的数量

    要想设置合理的线程数,需要区分任务是计算(CPU)密集型还是IO密集型

    计算密集型  针对计算密集型一般设置为CPU核数+1比较合理,因为是计算密集型,那么计算就要用CPU,设置为CPU的核数可以充分利用CPU的优势,至于为什么要加1,可以理解为计算密集型,也要有IO操作,加1是为了在等待IO的时候,充分利用CPU

    IO密集型  对应IO密集型,也就是说该任务涉及很多的IO操作,比如读写磁盘,远程RPC调用等,网上有很多数是设置为2*CPU核数+1,当然这也是可以的,不过下面这样设置可能更能发挥CPU的性能,CPU数*CPU利用率*(任务等待时间/任务计算时间+1),假如有个8核机器,任务有100ms在计算,800ms在等待IO,CPU的利用率为100%的话,线程数=8*1*(800/100+1)=72,当然现实场景中CPU的利用率不可能飙到100%,还要具体场景具体分析;

    线程池在tomcat中的使用

    tomcat作为servlet服务器,要处理请求,是为每个请求创建一个线程,那么它的配置是在哪里那,在tomcat的conf/server.xml文件中

    看上面有个Executor的配置实例,maxThreads的配置,看上图中例子给出的值为150。其实tomcat7/8默认的线程池大小为200.

    参考:https://joonwhee.blog.csdn.net/article/details/106609583

    一个爱写文章的程序员,欢迎关注我的公众号“北漂程序员”。我有故事,你有酒吗
  • 相关阅读:
    【转】ASP.NET配置文件详解
    asp.net 使用application实现单点登录(一个账号只能在一个地方登录)
    转:gridview获取当前行索引的方法
    awk中调用shell的自定义函数
    不想做操作工就把你的心静下来
    nagios通过脚本对系统进行定制监控
    关于一个sql执行时间而引发的讨论
    网站前端服务器高可用方案
    NFS在Centos 6.3下的安装
    关于perl中中文乱码的解决办法
  • 原文地址:https://www.cnblogs.com/teach/p/14641129.html
Copyright © 2011-2022 走看看