java 线程池ThreadPoolExecutor

                                              java 线程池ThreadPoolExecutor

一、线程池的作用
      1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
      2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
      3)提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

二、线程池ThreadPoolExecutor

   1.接口说明

 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
        BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
  各个参数的含义:

     corePoolSize:线程池维护线程的最少线程数,也是核心线程数,包括空闲线程。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;

    maximumPoolSize: 线程池维护线程的最大线程数,它表示在线程池中最多能创建多少个线程;

    keepAliveTime: 线程池维护线程所允许的空闲时间.表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。

   unit: 线程池维护线程所允许的空闲时间的单位,keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:

            TimeUnit.DAYS;                                                 //天
            TimeUnit.HOURS;                                           //小时
            TimeUnit.MINUTES;                                       //分钟
            TimeUnit.SECONDS;                                    //秒
            TimeUnit.MILLISECONDS;                         //毫秒
            TimeUnit.MICROSECONDS;                    //微妙
            TimeUnit.NANOSECONDS;                    //纳秒

   workQueue:用于保存等待执行的任务的阻塞队列,阻塞队列有以下几种选择:
                         ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。 
                        LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。
                       SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于                                    LinkedBlockingQueue

  threadFactory:线程工厂,主要用来创建线程

  handler: 线程池对拒绝任务的处理策略 有以下四种取值:
                      ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 
                      ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 
                      ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
                      ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 

   2.工作原理:

     任务通过execute(Runnable)方法添加到线程池,一个任务就是一个Runnable对象,任务的执行就是Runnable对象的run()方法.

      当一个任务将被添加到线程池中时:
               如果当前线程数小于corePoolSize,即使有空闲线程,也会创建新的线程来处理新增任务;
               如果当前线程数等于corePoolSize,如果缓冲队列未满,该任务被放入缓冲队列,池子里的空闲线程就去从workQueue中取任务并处理
               如果当前线程数大于corePoolSize,且冲队列已满,如果当前线程数小于maximumPoolSize, 就创建新的线程来处理新增任务;
               如果当前线程数等于maximumPoolSize,且冲队列已满,将会使用handler所指定的策略来处理任务.

    线程池处理任务的顺序是:
             核心线程corePoolSize,   缓冲队列workQueue,  最大线程maximumPoolSize
    当前线程数大于corePoolSize,线程池中的空闲线程在超过keepAliveTime, 会自动终止.线程池通过keepAliveTime来动态维护线程数.

3.代码

   

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class TestThreadPool {
	
	 public static void main(String[] args) {   
         ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 20, TimeUnit.MILLISECONDS,
                 new ArrayBlockingQueue<Runnable>(2), 
                 new ThreadFactory() {
                     private AtomicInteger threadIndex = new AtomicInteger(0);

                     @Override
                     public Thread newThread(Runnable r) {
                         return new Thread(r, "T" + this.threadIndex.incrementAndGet());
                     }
                 },
                 new ThreadPoolExecutor.DiscardOldestPolicy());
          
         for(int i=0;i<9;i++){
             MyTask myTask = new MyTask(i);
             System.out.println("创建任务并提交到线程池中:任务" + i);  
             executor.execute(myTask);
             System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+
             executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount());
         }
         executor.shutdown();
     }

}

class MyTask implements Runnable {
    private int taskNum;
     
    public MyTask(int num) {
        this.taskNum = num;
    }
     
    @Override
    public void run() {
        System.out.println("正在执行task "+taskNum+";Thread.currentThread().getName()="+Thread.currentThread().getName());
        try {
            Thread.currentThread().sleep(60000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task "+taskNum+"执行完毕"+";Thread.currentThread().getName()="+Thread.currentThread().getName());
    }
}

运行结果

 创建任务并提交到线程池中:任务0
正在执行task 0;Thread.currentThread().getName()=T1
线程池中线程数目:1,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
创建任务并提交到线程池中:任务1
线程池中线程数目:2,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
创建任务并提交到线程池中:任务2
正在执行task 1;Thread.currentThread().getName()=T2
线程池中线程数目:2,队列中等待执行的任务数目:1,已执行玩别的任务数目:0
创建任务并提交到线程池中:任务3
线程池中线程数目:2,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
创建任务并提交到线程池中:任务4
线程池中线程数目:3,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
创建任务并提交到线程池中:任务5
正在执行task 4;Thread.currentThread().getName()=T3
线程池中线程数目:4,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
正在执行task 5;Thread.currentThread().getName()=T4
创建任务并提交到线程池中:任务6
线程池中线程数目:4,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
创建任务并提交到线程池中:任务7
线程池中线程数目:4,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
创建任务并提交到线程池中:任务8
线程池中线程数目:4,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
task 0执行完毕;Thread.currentThread().getName()=T1
task 1执行完毕;Thread.currentThread().getName()=T2
正在执行task 7;Thread.currentThread().getName()=T1
正在执行task 8;Thread.currentThread().getName()=T2
task 5执行完毕;Thread.currentThread().getName()=T4
task 4执行完毕;Thread.currentThread().getName()=T3
task 7执行完毕;Thread.currentThread().getName()=T1
task 8执行完毕;Thread.currentThread().getName()=T2

对结果分析

  

               程序中一共有四个线程,分别是T1、T2、T3、T4.

                任务:task2、task3、task6被丢弃了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值