Java并发编程(你不知道的线程池操作)

               

     这几篇博客,一直在谈线程,设想一下这个场景,如果并发的线程很多,然而每个线程如果执行的时间很多的话,这样的话,就会大量的降低系统的效率。这时候就可以采用线程池的操作,来缓存我们并发操作的线程。

     而对于java中的线程池,大家需要理解好ThreadPoolExecutor、AbstractExecutorService、ExecutorService和Executor这几个类之间的关系即可。


     

     通过看上面的这个关系图,可以知道,最核心的一个类是ThreadPoolExecutor,我们下面来具体的看一下这个类的操作。


    ThreadPoolExecutor类提供了四个构造函数,如下所示


<span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;"><span style="font-family:Comic Sans MS;font-size:18px;">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) {  this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,    threadFactory, defaultHandler); } public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,   long keepAliveTime, TimeUnit unit,   BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {  this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,    Executors.defaultThreadFactory(), handler); } public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,   long keepAliveTime, TimeUnit unit,   BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,   RejectedExecutionHandler handler) {  if (corePoolSize < 0 || maximumPoolSize <= 0    || maximumPoolSize < corePoolSize || keepAliveTime < 0)   throw new IllegalArgumentException();  if (workQueue == null || threadFactory == null || handler == null)   throw new NullPointerException();  this.corePoolSize = corePoolSize;  this.maximumPoolSize = maximumPoolSize;  this.workQueue = workQueue;  this.keepAliveTime = unit.toNanos(keepAliveTime);  this.threadFactory = threadFactory;  this.handler = handler; }</span></span></span>


     下面来分析下这四个构造函数中每个参数的具体意义,其实主要是一些初始化的操作


        corePoolSize:表明这个线程池的大小

     maximumPoolSize:表明这个线程池中,最多可以容纳多少个线程执行

     TimeUnit:线程存活的时间单位,有秒、小时、分钟等

     keepAliveTime:用来表示一个线程多长时间不执行任务后,就被废弃掉

     workQueue:阻塞队列,表示如何线程多余线程池的话,用来存储等待执行的任务,具体值如下


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

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

       3)synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。


       threadFactory:一个线程工厂,用来创建线程

     handler:用来表示拒绝执行任务的策略。


    下面通过举个例子来理解上述的表示参数。


     假如有一个工厂,工厂里面有10个工人,每个工人同时只能做一件任务。 因此只要当10个工人中有工人是空闲的,来了任务就分配给空闲的工人做;当10个工人都有任务在做时,如果还来了任务,就把任务进行排队等待;如果说新任务数目增长的速度远远大于工人做任务的速度,那么此时工厂主管可能会想补救措施,比如重新招4个临时工人进来;然后就将任务也分配给这4个临时工人做;如果说着14个工人做任务的速度还是不够,此时工厂主管可能就要考虑不再接收新的任务或者抛弃前面的一些任务了。当这14个工人当中有人空闲时,而新任务增长的速度又比较缓慢,工厂主管可能就考虑辞掉4个临时工了,只保持原来的10个工人,毕竟请额外的工人是要花钱的。


     这个例子中的corePoolSize就是10,而maximumPoolSize就是14(10+4)。

     也就是说corePoolSize就是线程池大小,maximumPoolSize在我看来是线程池的一种补救措施,即任务量突然过大时的一种补救措施。


     下面通过一个例子来了解上述的构造函数。

 

<span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;"><span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;font-size:18px;">package com.test;import java.util.concurrent.LinkedBlockingQueue;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;public class TestThreadPool {      public static void main(String[] args) {       //创建一个线程池        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3, 6, 5,TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());          //通过循环来开启20个任务操作         for (int i = 1; i <= 20; i++) {                threadPool.execute(new ThreadPoolTask());          }      }  } //创建 ThreadPoolTask类: class ThreadPoolTask implements Runnable {      public void run() {          try {              System.out.println("开始执行任务:" + Thread.currentThread().getName());                   Thread.sleep(100);          }        catch(Exception e){              e.printStackTrace();          }      }   }</span></span></span></span>
 

     上面就是开启20个任务,来让线程池处理,如果线程池满了的话,就会放入到阻塞对列中进行等待操作


     不过在java doc中,并不提倡我们直接使用ThreadPoolExecutor,而是使用Executors类中提供的几个静态方法来创建线程池:

       Executors.newCachedThreadPool();        //创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE

    Executors.newSingleThreadExecutor();   //创建容量为1的缓冲池
    Executors.newFixedThreadPool(int);    //创建固定容量大小的缓冲池


     下面是这三个静态方法的具体实现;

<span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;"><span style="font-family:Comic Sans MS;font-size:18px;">public static ExecutorService newFixedThreadPool(int nThreads) {    return new ThreadPoolExecutor(nThreads, nThreads,                                  0L, TimeUnit.MILLISECONDS,                                  new LinkedBlockingQueue<Runnable>());}public static ExecutorService newSingleThreadExecutor() {    return new FinalizableDelegatedExecutorService        (new ThreadPoolExecutor(1, 1,                                0L, TimeUnit.MILLISECONDS,                                new LinkedBlockingQueue<Runnable>()));}public static ExecutorService newCachedThreadPool() {    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                  60L, TimeUnit.SECONDS,                                  new SynchronousQueue<Runnable>());}</span></span></span>

     从它们的具体实现来看,它们实际上也是调用了ThreadPoolExecutor,只不过参数都已配置好了。

                   newFixedThreadPool创建的线程池corePoolSize和maximumPoolSize值是相等的,它使用的LinkedBlockingQueue;

            newSingleThreadExecutor将corePoolSize和maximumPoolSize都设置为1,也使用的LinkedBlockingQueue;

            newCachedThreadPool将corePoolSize设置为0,将maximumPoolSize设置为Integer.MAX_VALUE,使用的SynchronousQueue,也就是说来了任务就创建线程运行,当线程空闲超过60秒,就销毁线程。


     实际中,如果Executors提供的三个静态方法能满足要求,就尽量使用它提供的三个方法,因为自己去手动配置ThreadPoolExecutor的参数有点麻烦,要根据实际任务的类型和数量来进行配置。


     另外,如果ThreadPoolExecutor达不到要求,可以自己继承ThreadPoolExecutor类进行重写。

     
     参考资料:

           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

猜你喜欢

转载自blog.csdn.net/qq_43747119/article/details/86909309