zoukankan      html  css  js  c++  java
  • java 线程池第一篇 之 ThreadPoolExcutor

    一:什么是线程池?

      java 线程池是将大量的线程集中管理的类,包括对线程的创建,资源的管理,线程生命周期的管理。当系统中存在大量的异步任务的时候就考虑使用java线程池管理所有的线程。减少系统资源的开销。

    二:线程池工厂类有多少种?

      java1.8 的官方文档提供了三种线程池工厂类,每种线程池工厂类型对应不同线程管理方式(策略)。

      newCachedThreadPool(自动废弃回收):

      当有可用的空闲线程,优先使用空闲线程,当没有可用的空闲线程的时候就创建新的线程。空闲线程超过60s没有被使用,将会关闭并从线程缓冲区中删除。这种设计的好处就是当并发高峰期过了之后,大量的空闲线程就会被回收,节省系统资源。

      newFixedhreadPool(固定线程池大小):

      首先创建一个固定线程大小的线程池,将所有的线程激活,创建一个无界任务队列存放所有的任务,当线程池中有可用的空闲线程,队列的任务就会被消费,当线程池中没有空闲线程,任务队列中的任务就等待,直到有线程被空出。当某个线程应为运行期间被异常关闭,其他的线程将会接替其运行后来的任务。这种线程池的好处就是不会再高峰的时候一直创建新的线程。线程空闲的时候也不会被销毁。除非程序员手动明确的调用关闭线程池的方法。                 

      newSingleThreadExecutor(单工作线程): 任何时候都只有一个线程被激活处理无界任务队列,当运行中的线程因为异常而关闭的时候,新的线程将被创建,这样的线程池将保证所有的任务顺序执行。

    三:测试线程池demo

    package test.thread.threadPool;


    import org.junit.Test;

    import java.util.concurrent.*;

    /**
    * 线程池
    */
    public class ThreadPool {

    /**
    * @version 经过测 试发现Junit的@Test注解不支持多线程,当单元测试的线程关闭之后,就会关闭所有的线程
    * @see @Test 注解会调用System.exit(0); 方法退出程序异步线程无法执行
    */
    public static void main(String[] args){
    /*
    * 创建一个线程的实例
    * 核心线程大小5
    * 最大线程大小10
    * 线程没有处理任务的时候存活的时间
    * 创建一个数组阻塞队列(队列的长度为5)
    * */
    ThreadPoolExecutor executor = new ThreadPoolExecutor(5,10,8000,
    TimeUnit.MILLISECONDS, new LinkedBlockingDeque<Runnable>());
    for(int i=0;i<15;i++){
    MyTask myTask = new MyTask(executor);
    //两种方法调用将任务加入到阻塞队列中submit(Runnable) 和 excute(Runnable) 方法
    executor.submit(myTask); //线程执行完毕返回一个future对象
    }
    }


    }
    class MyTask implements Runnable {

    private ThreadPoolExecutor executor;

    public MyTask(ThreadPoolExecutor ex){
    this.executor=ex;
    }


    @Override
    public void run() {
    synchronized (executor) { //加锁监视器的目的是应为多个线程修改数据,调用get方法可能获取数不对
    System.out.println("线程-" + Thread.currentThread().getId() + ":正在执行task ");
    try {
    //线程休眠三秒更直观的查看效果
    Thread.sleep(1);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("线程池中核心线程数目:" + executor.getPoolSize() + ",队列中等待执行的任务数目:" +
    executor.getQueue().size() + ",已执行完成的任务数目:" + executor.getCompletedTaskCount());
    }
    }
    }

    源码解析:ThreadPoolExecutor 是线程池的核心类,他有四个构造函数,分别是为了选择不同的线程工厂策略,异常处理,任务管理。

     public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {
            this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                 Executors.defaultThreadFactory(), defaultHandler);  //默认线程工厂和处理器
    }
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,
    ThreadFactory threadFactory)
    public ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    RejectedExecutionHandler handler)
    public ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    ThreadFactory threadFactory,
    RejectedExecutionHandler handler)

      corePoolSzie:这个参数是线程池的核心参数,表示当前线程数小于corePoolSize的时候,线程池每接收一个新的任务将创建一个新的线程,即使有空闲的线程也不会复用。 

      maximumPooSize:最大线程池拥有的线程数,当线程池中的线程数大于corePoolSize的时候,先复用corePoolSize中的空闲线程,当没有空闲线程的时候就创建新的线程,但是线程的总数不会超过maximunPoolSize.

      keepAliveTime:非核心线程能存活的最大时间。当线程数超过corePoolSize的时候,当有空闲的线程时间超过keepAliveTime将会被回收。

      unit:时间的单位,用TimeUnits这个类的类属性。属性包含NANOSECONDS,MICROSECONDS,MILLISECONDS,SECONDS,MINUTES,HOUR,DAYS

      workQueue:线程池将要消费的任务,这个任务的类型必须是线程,要继承Runnable 的接口,就这是为什么要叫线程池,对于阻塞队列,一般会有ArrayBlockQque,LinkedBlockQueue,synchronousQueue 三种。

      defaultHandlerExecutor:默认的拒绝策略,当线程池关闭的时候,新的任务将被拒绝,并且展现不同的处理策略

      注意:excutor.shutDown(); 方法是将线程池关闭,已经在线程池中的任务将会继续执行,没有被接受的任务将不会在处理。

         当线程池的队列用的ArrayBlockQque 的时候,若线程池中的所有线程都被用完,并且还有任务进入队里将会抛出RejectedExecutionException

    四:方法解析

      ThreadExcutor 类最高继承接口Executor,Executor 这个接口只生命了一个方法:execute(Runnable commond) 

      类uml图

    Executor 接口:execute(Runnable commond) 方法是调用线程的核心方法

    ExecutorService 接口:提供了管理异步线程的方法。

        shutdown() :将当前正在执行的异步任务继续执行,不再接受新的任务进入线程池。

        shutdownNow():将当前正执行的线程关闭,不在接受新的任务进入线程池。

        submit():将任务提交到线程池中,并且会返回Future对象。底层调用的是Runnable 的run()方法或者是callable 的call()方法

    AbstractExecutorService: 实现了submit 方法,提供线程返回值,但是这种线程的执行是直接的调用的run() 方法,导致最后线程池所有的线程都是顺序执行,并不是异步的

    ThreadExecutor 提供了创建线程池的构造函数,以及拒绝策略,还有各种监控线程执行状态的方法。

      

      

      

  • 相关阅读:
    实验室资质认定评审准则和要素及要点
    如何进行内审?
    实验室比对结果评价的3种方法
    第一次如何申请CNAS实验室认可资质
    风险评估的实施步骤
    Servlet
    CMMI_SCAMPY评估方法
    PHP_2
    PHP_1
    java中String与StringBuilder的区别
  • 原文地址:https://www.cnblogs.com/blogxiao/p/9198590.html
Copyright © 2011-2022 走看看