zoukankan      html  css  js  c++  java
  • 线程池原理相关问题

    工作中常用线程池的(通过Executors)创建方法分为以下四种:

    newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

    newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

    newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

    newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

    查看源码可知,他们底层都是用ThreadPoolExecutor实现的:

    ThreadPoolExecutor线程池-->继承AbstractExecutorService类-->实现ExecutorService接口-->继承Executor类

    面试中也经常会问线程池的参数问题:

    常用的五个参数: new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);

    corePoolSize:核心池的大小。创建线程池后,默认池中没有线程,有任务的时候才会去创建(当池中线程数目达到corePoolSize后会把到达的任务放到缓存队列中);

          如果调用prestartAllCoreThreads()或者prestartCoreThread()方法,才会在没有任务的时候就预先创建corePoolSize个线程或者一个线程。

    maximumPoolSize:线程池中最大线程数

    keepAliveTime:线程没有执行任务时,最多保持多久会终止。默认当线程数量超过corePoolSize时,keepAliveTime起作用,如果调用了allowCoreThreadTimeOut(fasle)时,不管线程数量多少,keepAliveTime都会起作用

    unit:keepAliveTime的单位(TimeUnit.DAYS/HOURS/MINUTES/SECONDS/MILLISECONDS/MICROSECONDS/NANOSECONDS)

    workQueue:一个阻塞队列,用来存储等待执行的任务,常用的有LinkedBlockingQueue和SynchronousQueue,ArrayBlockingQueue和PriorityBlockingQueue使用较少

    public class ThreadPoolDemo {
    
        public static class MyTask implements Runnable {
    
            public void run() {
                System.out.println(System.currentTimeMillis() + ":Thread ID:" + Thread.currentThread().getId());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
        public static void main(String[] args) {
            // 当线程池中线程的数目大于5时,便将任务放入任务缓存队列里面,当任务缓存队列满了之后,便创建新的线程。
            // 如果上面程序中,将for循环中改成执行20个任务,就会抛出任务拒绝异常了。
         // ThreadPoolExecutor exec = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(5));
            // ArrayBlockingQueue(有界阻塞队列--必须指定大小)和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue(无界阻塞队列)和Synchronous。线程池的排队策略与WorkQueue有关。
            ThreadPoolExecutor exec = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<Runnable>());
            // 创建一个可根据实际情况调整线程数量线程池
            for (int i = 0; i < 15; i++) {
                MyTask myTask = new MyTask();
                exec.submit(myTask);
                System.err.println("线程池中线程数目:" + exec.getPoolSize() + ",队列中等待执行的任务数:" + exec.getQueue().size()
                        + ",已执行完别的任务数:" + exec.getCompletedTaskCount());
            }
            exec.shutdown();
        }
    
    }

    使用new ArrayBlockingQueue<>(5),开启15个线程,输出如下:

    使用new ArrayBlockingQueue<>(5),开启20个线程,输出如下:

    使用new LinkedBlockingDeque<>(),开启20个线程,输出如下:

     

    newFixedThreadPool和newCachedThreadPool有什么区别?

    newFixedThreadPool该方法返回一个固定数量的线程池,当一个新任务提交时,线程池中若有空闲线程,则立即执行;

              若没有,则新的任务会被暂存到一个任务队列中,待有空闲线程时再进行处理。

    newCachedThreadPool该方法返回一个可根据实际情况调整线程数量的线程池。当一个新任务提交时,若有空闲的线程

              可以复用则优先使用可服用的线程;若没有,则创建新的线程来处理任务。当任何一个线程处理完当前任务后都将返回到线程池中以备复用。

    为什么不用newCachedThreadPool?

    newCachedThreadPool的maximumPoolSize 最大值Integer.MAX_VALUE,一般来说机器都没有这么大内存供他使用,比如

    在JDK1.5以后一个线程的堆栈大小为1M及-Xss1024k如果一下有10000个线程10000*1M=约10G的内存空间供给线程使用,这个是不现实的。

  • 相关阅读:
    RDIFramework.NET V3.3 WinForm版新增日程管理功能模块
    RDIFramework.NET V3.3 WinForm版角色授权管理新增角色对操作权限项、模块起止生效日期的设置
    RDIFramework.NET V3.3 Web版角色授权管理新增角色对操作权限项、模块起止生效日期的设置
    前端神器-神级代码编辑软件Sublime Text下载、使用教程、插件推荐说明、全套快捷键
    C# net request payload形式发送post请求
    RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.2版本正式发布
    RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.2->WinForm版本重构岗位授权管理界面更规范、高效与美观
    NET快速信息化系统开发框架 V3.2 ->WinForm部分全部重构为Dev风格界面
    NET快速信息化系统开发框架 V3.2 -> “用户管理”主界面使用多表头展示、增加打印功能
    SQLServer特殊字符/生僻字与varchar
  • 原文地址:https://www.cnblogs.com/java-spring/p/10794299.html
Copyright © 2011-2022 走看看