zoukankan      html  css  js  c++  java
  • 线程池的问题

    一、什么是线程池?

      一个线程池管理一组工作的线程,同时它还包括一个用于放置等待执行任务的任务队列(阻塞队列)。

    二、线程池的工作原理

      默认情况下,在创建线程池后,线程池中的线程数为0,当任务提交给线程池后处理策略如下:

      1. 如果线程池中的数量小于 corePoolSize(核心线程池大小),即使线程池中的线程都处于空闲状态,也要创建一个新的线程来处理被添加的任务。

      2. 如果线程池中的数量大于等于corePoolSize,但是缓冲队列 WorkQueue 未满,那么任务被放入到缓冲队列,则该任务会等待空闲线程将其去出去执行。

      3. 如果线程池中的数量大于等于corePoolSize,而且缓冲队列 WorkQueue 已满,并且线程池中的数量小于最大线程数 MaximumPoolSize,则建新的线程来处理被添加的任务。

      4. 如果线程池中的数量大于等于corePoolSize,而且缓冲队列 WorkQueue 已满,并且线程池中的数量等于最大线程数 MaximumPoolSize,则通过RejectedExceptionHandler所指定的策略(任务拒绝策略)来处理此任务。

      即处理任务的优先级为:corePoolSize -> WorkQueue -> MaximumPoolSize,如果3这都满,则交给 RejectedExceptionHandler 处理被拒绝的任务。

      5. 特别注意:在 corePoolSize 和 MaximunPoolSize 之间的线程会被自动释放。当线程数量大于corePoolSize时,如果某个线程空间超过KeepAliveTime,线程将被终止,直至线程池中线程数量不大于corePoolSize。这样,线程池可以动态调节池中线程的数量。

    三、使用线程池的好处

      1. 通过重复利用已创建的线程,减少在创建和销毁线程上所花的时间以及系统资源的开销。

      2. 提高相应速度。当任务到达时,任务可以不需要等到线程创建就可以执行。

      3. 提高线程的可管理性。使用线程池可以对线程统一的分配和监控。

      4. 如果不使用线程池,系统会创建大量的线程导致消耗完系统内存。

    四、线程池的创建

    1. 接口与抽象类

      Executors 类(推荐)

      Executor 接口

      ExecutorService 接口

      AbstractExecutorService 抽象类

      ThreadPoolExecutor 类(不推荐)

     继承关系:Executor <- ExecutorService <- AbstractExecutorService <- ThreadPoolExecutor

    2. Executors 类:(推荐使用)
      它主要用来创建线程池。
      Executors.newSingleThreadExecutor(); //创建容量为1 的线程池
      Executors.newFixedThreadPool(int n); //创建固定容量大小的线程池
      Executors.newCachedThreadPool(); //创建一个线程池,线程池最大容量为 Integer.MAX_VALUE(无界线程池)

     1 public static void testExecutor() {
     2         //ExecutorService service = Executors.newSingleThreadExecutor();
     3         ExecutorService service = Executors.newFixedThreadPool(2);//创建两个线程
     4         service.submit(new Runnable() {
     5             @Override
     6             public void run() {
     7                 for (int i = 0; i < 10; ++i) {
     8                     try {
     9                         Thread.sleep(1000);
    10                         System.out.println("Executor1:" + i);
    11                     } catch (Exception e) {
    12                         e.printStackTrace();
    13                     }
    14                 }
    15             }
    16         });
    17 
    18         service.submit(new Runnable() {
    19             @Override
    20             public void run() {
    21                 for (int i = 0; i < 10; ++i) {
    22                     try {
    23                         Thread.sleep(1000);
    24                         System.out.println("Executor2:" + i);
    25                     } catch (Exception e) {
    26                         e.printStackTrace();
    27                     }
    28                 }
    29             }
    30         });
    31 
    32         service.shutdown();
    33         while (!service.isTerminated()) {
    34             try {
    35                 Thread.sleep(1000);
    36                 System.out.println("Wait for termination.");
    37             } catch (Exception e) {
    38                 e.printStackTrace();
    39             }
    40         }
    41     }

    3. ThreadPoolExecutor 类

    1 public ThreadPoolExecutor(int corePoolSize,
    2                               int maximumPoolSize,
    3                               long keepAliveTime,
    4                               TimeUnit unit,
    5                               BlockingQueue<Runnable> workQueue,
    6                               RejectedExecutionHandler handler);

      corePoolSize:核心线程数。

      maximunPoolSize:线程池最大线程数

      keepAliveTime:默认情况下,线程池线程数大于 corePoolSize 后,keepAliveTime 才起作用,如果一个线程空闲时间达到 keepAliveTIme,则会终止,直到线程数不超过 corePoolSize

      unit:参数keepAliveTime的 的时间参数

      workQueue:阻塞队列,任务缓存队列,存放等待执行的任务

        workQueue 的类型为BlockingQueue接口 ,有三种实现类型:

        1)ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;

        2)LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE;

        3)synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。在某次添加元素后必须等待其他线程取走后才能继续添加

      ThreadFactor:线程工厂,用来创建线程

      handler:表示当拒绝任务时的策略,有以下取值:

        1.AbortPolicy:直接抛出异常(默认的)

        2.DiscardPolicy:直接丢弃任务

        3.DiscardOldestPolicy:丢弃队列中最旧(队头)的任务,并执行当前任务

        4.CallerRunsPolicy:不用线程池中的线程执行,用调用者所在线程执行

    ThreadPoolExecutor 有以下几个非常重要的方法:

      execute()

      submit()

      shutdown()

      shutdownNow()

    execute() 与 submit() 的区别:

      1. submit 有返回值,execute 没有返回值。所以说可以根据任务有无返回值选择对应的方法。  

      2.  submit 方便异常的处理。如果任务可能会抛出异常,而且希望外面的调用者能够感知这些异常,那么就需要调用submit 方法,通过捕获Future.get抛出的异常。

    shutdown() 与 shutdownNow() 的区别:

      1.都是用来关闭线程池的。

      2. shutdown 方法:此方法执行后不得向线程池再提交任务,如果有空闲线程则销毁空闲线程,等待所有正在执行的任务及位于阻塞队列中的任务执行结束,然后销毁所有线程。

      3. shutdownNow 方法:此方法执行后不得向线程池再提交任务,如果有空闲线程则销毁空闲线程,取消所有位于阻塞队列中的任务,并将其放入List<Runnable>容器,作为返回值。取消正在执行的线程(实际上仅仅是设置正在执行线程的中断标志位,调用线程的interrupt 方法来中断线程)。

  • 相关阅读:
    jQuery 基本选择器
    JavaScriptif while for switch流程控制 JS函数 内置对象
    JavaScrip基本语法
    数据库 存储引擎 表的操作 数值类型 时间类型 字符串类型 枚举集合 约束
    数据库基础知识 管理员 用户登录授权的操作
    粘包的产生原理 以及如何解决粘包问题
    socket TCP DPT 网络编程
    2018年年终总结
    Android技术分享
    No accelerator found
  • 原文地址:https://www.cnblogs.com/yumingxing/p/9555919.html
Copyright © 2011-2022 走看看