暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Java高并发编程系列(一)线程池

码农的修炼之道 2018-08-27
169

写本文起源于某朋友的面试中问道线程池相关的问题,看完本文,你会了解线程池。

我们预先留下3个问题。

(1)线程池有哪些参数?

(2)有哪些类型的线程池?有什么区别?

(3)有哪些拒绝策略?

1、什么是线程池

       线程池其实就是有多个线程的池子,通过维护一定数量的线程从而达到减少创建和销毁线程的损耗,从而提高资源的利用率。如果我们不用线程池,那么我们只能自己new Thread进行创建线程,而且销毁也是一件麻烦的事情。现在这些可以全部交给线程池完成。

2、线程池核心类

     在Java.util.concurrent包下包括了我们所有高并发编程的类和接口。这个包下分为三部分:

(1)atomic子包:该包下包含了高并发场景下的数据类型的操作。比如AtomicInteger类等。

(2)locks子包:该包下包括了高并发变成常用的锁。比如我们熟悉的Lock接口、ReentrantLock类、ReadWriteLock接口(读写锁)等。

(3)其他类。这些类直接在Java.util.concurrent 包下。这里面我们可以分为三类。第一,并发场景下的安全数据类型,比如ConcurrentHashMap类、BlockingQueue接口及相关类等。第二,定时器相关的。比如DelayQueue等。第三,就是线程池相关的类。

      我们先来看看Excutors类。这个类是线程池相关的核心类了。这里我们可以看到熟悉的大神Doug Lea。

     在这个类中,我们看一下有哪些方法。

       这个类的构造函数被标志为private,说明这个类不能被创建。调用方法只能通过静态方法调用,这也就是单例设计模式。

      接下来我们看看这个类中的方法,都是静态方法,创建各种线程。同时,这个类中还定义了一些静态内部类。有一个特殊的内部类如下所示:

     下面我们介绍的线程池中默认采用的默认的线程工厂,其实就是在这里实现的。从这个类中,我们可以看出线程的命名方式为“pool-自增的数字-thread-”,这个自增的数字就是采用AtomicInteger

     我们可以从Excutors类看出,这就是一个静态工厂类,调用者可以通过这个类来得到想要的线程池。这个里面核心的类就是ThreadPoolExcutor类。

      我们进入这个类来看看。首先看看这个类的构造函数。

  • corePoolSize:线程核心大小,也可以理解为最小线程池大小。

  • maximumPoolSize:最大线程池大小。

  • keepAliveTime:空余线程存活时间,意思就是超过corePoolSize大小的线程经过这么长时间才能进行销毁。

  • unit:时间单位,有秒、毫秒等。

  • workQueue:这个是线程队列,里面存储每一个提交的任务,每个任务也就是一个Runnable对象。

  • threadFactory:线程工厂,这里使用了在Excutors类中定义好的内部类defaultThreadFactory。

  • RejectedExecutionHandler:拒绝策略,每次看到Handler类,可以任务这是一种策略。这里主要指当线程池满了(满负荷工作或阻塞),工作队列也满了,如何拒绝新的任务。

3、线程池分类

     我们上面在Excutors类中已经看到了常用的几种线程池类型。

  • newFixedThreadPool


           这是固定的线程池,核心线程和最大线程相等。而且存活时间为0.指定的工作队列为LinkedBlockingQueue。这里指定的拒绝策略为default,也就是AbortPolicy类。

  • newCachedThreadPool

  •         这是带缓冲区的线程池,从构造函数可以看出,这个线程池的核心线程为0,最大线程为Integer.MAX_VALUE。超过60秒,那么就会销毁线程。这里的工作队列采用的是SynchronousQueue。这个队列的用处在于,如果有空闲线程(还没到60s销毁时间),那么就直接执行任务。假如没有线程,那么就创建一个线程执行任务。

    • newSingleThreadExcutor


           Excutors类中提供的这两个方法,其默认核心线程数和最大线程数都是1.也就是单线程模式。其默认的工作队列是LinkedBlockingQueue。相当于每次有新任务到来,都会加入工作队列中,线程从工作队列中依次取出任务进行处理。

    • newScheduledThreadPool

          这是支持任务调度的线程池,也就是按照一定的周期进行调度任务,相当于定时器任务。这个底层是对ThreadPoolExcutor进行包装了。

       我们可以进这个ScheduledThreadPoolExcutor类看看。

            这个类的构造函数调用了父类的构造函数,这里指定了一个DelayedWorkQueue传递到父类构造函数中。那么我看看这个类如何定义的

           原来这个ScheduledThreadPoolExcutorThreadPoolExcutor的子类,只是指定了父类的工作队列为DelayedWorkQueue。同时这个类还实现了ScheduledExcutorService接口,这个接口中的方法都是Schedule相关的,有兴趣的可以点进去看看。

           下一篇文章,我们将介绍线程池中常用的拒绝策略


文章转载自码农的修炼之道,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论