zoukankan      html  css  js  c++  java
  • 线程6-线程池

    1、几个概念:
    (1)线程池 ThreadPoolExecutor:存放线程的池子( --!)
    (2)线程 Thread:用于执行实现<Runnable>接口的任务
    (3)任务缓存队列:用于存放Thread要执行的任务
    2、几个变量和方法的解释
    (1)ThreadPoolExecutor的构造方法参数
    corePoolSize:核心池的大小,在创建了线程池后,默认情况下,线程数为0。当有任务来了之后,就创建一个线程
    去执行任务,当线程池中的线程数达到corePoolSize之后,就会尝试把新到达的任务放到缓存队列中
    maximumPoolSize:线程池中最大线程数
    keepAliveTime:线程池中的某个线程在多久没有执行任务时,线程会终止
    unit:参数keepAliveTime的时间单位,有7种取值,参见TimeUnit类
    workQueue:一个阻塞队列,用来存储等待执行的**任务**(非线程),阻塞队列有以下几种选择
    一般使用LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。
    (2)execute()方法,可向线程池提交一个任务,交由线程池去执行
    (3)submit()方法,也是向线程池提交一个任务,它能够返回任务结果,看源码可知,
    其实submit()也是调用了execute,只不过它使用了RunnableFutureo类来获取线程执行结果
    (4)shutdown(),等所有任务执行完毕后,关闭线程池
    (5)shutdownNow(),马上关闭线程池,不管任务是否完成
    (6)拒绝策略,通常有以下4种策略
    ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
    ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
    ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
    ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
    (7)任务缓存队列及排队策略
    任务缓存策略,即workQueue,用来等待任务执行的任务
    workQueue通常有以下3种类型
    1)ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;
    2)LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE(0x7fffffff);
    3)synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。
    (8)在ThreadPoolExecutor类中定义了一个volate变量,用来指示线程池状态,线程池有4种状态
    1)static final int RUNNING = 0;
    2)static final int SHUTDOWN = 1;
    3)static final int STOP = 2;
    4)static final int TERMINATED = 3;
    创建后,线程池处于RUNNING状态
    shutdown()后,线程处于SHUTDOWN状态,此时它只等待所有线程执行完任务,不接受新任务
    shotdownNow()后,线程处于STOP状态,它不接受任务,尝试终止正在执行的任务
    线程池处于STOP状态后,并且所有工作线程已销毁,任务缓存队列已清空或执行结束后,线程池被置为TERMINATED(结束)状态
    3、线程池的工作流程
    创建线程池(ThreadPoolExecutor)时,会指定核心池(corePoolSize)和线程池的最大线程容量(maximumPoolSize)
    (1)创建线程池,线程池中线程为0,任务缓存队列中的任务为0
    (2)ThreadPoolExecutor对象使用execute方法,向线程池提交一个任务
    (3)线程池拿到任务,进行判断
    如果当前线程池中的线程数,=<corePoolSize,创建一个新线程去执行任务
    如果当前线程池中的线程数,大于corePoolSize并且小于maximumPoolSize,
    则线程池会尝试把任务放到任务缓存队列,
    如果放入缓存队列失败(一般来说是任务缓存队列已满),线程池尝试创建线程来执行任务
    放入缓存队列成功,任务就等待空闲线程来取出执行
    如果当前线程池中的线程数,等于maximunPoolSize,
    则线程池会尝试把任务放到任务缓存队列,
    如果放入缓存队列成功,任务就等待空闲线程来取出执行
    如果放入缓存队列失败(一般来说是任务缓存队列已满),则会采取拒绝策略进行处理
    4、线程池例子

    package com.线程池;
    
    import java.util.concurrent.LinkedBlockingDeque;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    public class Test {
        public void testThread() throws InterruptedException {
             
            /**线程池构造方法中
             *  public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue)
                   (1)corePoolSize:核心池的大小,在创建了线程池后,默认情况下,线程数为0当有任务来了之后,就创建一个线程
                   去执行任务,当线程池中的线程数达到corePoolSize之后,就会把新到达的任务放到缓存队列中
                   (2)maximumPoolSize:线程中最大线程数
                   (3)keepAliveTime:线程池中的某个线程在多久没有执行任务时,会终止
                   (4)unit:参数keepAliveTime的时间单位,有7种取值,参见TimeUnit类
                   (5)workQueue:一个阻塞队列,用来存储等待执行的**任务**(非线程),阻塞队列有以下几种选择:
                   ArrayBlockingQueue;
                LinkedBlockingQueue;
                SynchronousQueue;
                ArrayBlockingQueue和PriorityBlockingQueue使用较少,
                一般使用LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。
             */
            ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS,
                    new LinkedBlockingDeque<Runnable>(6));//参数6是阻塞队列的容量
            
            //执行任务
            for(int i = 0 ; i < 15 ; i ++){
                MyMask mask = new MyMask(i);
                /**
                 * ThreadPoolExecutor的四个方法
                 * (1)execute()方法,可向线程池提交一个任务,交由线程池去执行
                 * (2)submit()方法,也是向线程池提交一个任务,它能够返回任务结果,看源码可知,
                 *     其实submit()也是调用了execute,只不过它使用了RunnableFutureo类来获取线程执行结果
                 * (3)shutdown(),等所有任务执行完毕后,关闭线程池
                 * (4)shutdownNow(),马上关闭线程池,不管任务是否完成
                 */
                 
                executor.execute(mask);
                System.out.println("线程池中的线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数:"+executor.getQueue().size()
                        +",已执行完的任务数:"+executor.getCompletedTaskCount());
                //Thread.currentThread();
                //Thread.sleep(2000);
            }
            executor.shutdown();
            
        }
        public static void main(String[] args) {
            Test test = new Test();
            try {
                test.testThread();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
    class MyMask implements Runnable{
        private Integer intNum;
        
        public MyMask(int num){
            this.intNum = num;
        }
    
        @Override
        public void run() {
            System.out.println("正在执行task "+intNum);
            
            Thread.currentThread();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("task "+intNum+"执行完成");
            
        }
        
    }

    参考:http://www.cnblogs.com/dolphin0520/p/3932921.html 原文写的很棒,讲的非常清晰,这篇博客是我按照自己的理解方式,重新整理了一下。

  • 相关阅读:
    配置YUM源出现Errno 14 Could not open/read repomd.xml 错误的解决办法
    Kubernetes imagePullPolicy拉取策略
    搭建高可用Kubernetes集群之etcd v3.4.13集群搭建(一)
    centos7启用 kubectl 自动补全
    jvm虚拟机
    音频EQ(均衡器)
    EDID:识别和解决常见问题指南(转)
    按键板的原理与实现 扩展GPIO(转)
    Tuner工作原理详解(转)
    STM32+W5500实现Web2个网页之间的切换(转)
  • 原文地址:https://www.cnblogs.com/fubaizhaizhuren/p/5067134.html
Copyright © 2011-2022 走看看