魅力峰值

导航

java线程池的创建、分类、以及理解

ThreadPoolExecutor

它的构造函数:

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) 

各个参数:

  corePoolSize - 线程池核心池的大小。
  maximumPoolSize - 线程池的最大线程数。
  keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
  unit - keepAliveTime 的时间单位。
  workQueue - 用来储存等待执行任务的队列。
  threadFactory - 线程工厂。
  handler - 拒绝策略。

 线程池大小

线程池有两个线程数的设置,一个为核心池线程数,一个为最大线程数。
创建了线程池后,默认情况下,线程池中并没有任何线程,等到有任务来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法;
当创建的线程数等于 corePoolSize 时,会加入设置的阻塞队列。当队列满时,会创建线程执行任务直到线程池中的数量等于maximumPoolSize。

阻塞队列选择

队列满了之后抛出:java.lang.IllegalStateException: Queue full
插入方法 add(e) offer(e) put(e) offer(e,time,unit)
移除方法 remove() poll() take() poll(time,unit)
检查方法 element() peek() 不可用 不可用

常见的如下:

1、ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。此队列按照先进先出(FIFO)的原则对元素进行排序
2、LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。此队列按照先进先出的原则对元素进行排序
3、PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。默认情况下元素采取自然顺序升序排列。继承Comparable类实现compareTo()方法来指定元素排序规则,或者初始化PriorityBlockingQueue时,指定构造参数Comparator来对元素进行排序。需要注意的是不能保证同优先级元素的顺序。

4、DelayQueue: 一个使用优先级队列实现的无界阻塞队列。支持延时获取元素的无界阻塞队列。队列使用PriorityQueue来实现。队列中的元素必须实现Delayed接口,在创建元素时可以指定多久才能从队列中获取当前元素。只有在延迟期满时才能从队列中提取元素.DelayWorkQueue 是 ScheduledThreadPoolExecutor的内部实现类,原理与DelayQueue基本一致

5、SynchronousQueue: 一个不存储元素的阻塞队列 ,每一个put操作必须等待一个take操作,否则不能继续添加元素。特征:插入元素到队列的线程被阻塞,直到另一个线程从队列中获取了队列中存储的元素。同样,如果线程尝试获取元素并且当前不存在任何元素,则该线程将被阻塞,直到线程将元素插入队列。
6、LinkedTransferQueue: 一个由链表结构组成的无界阻塞队列。相对于其他阻塞队列,LinkedTransferQueue多了tryTransfer(tryTransfer方法是用来试探生产者传入的元素是否能直接传给消费者。如果没有消费者等待接收元素,则返回false。和transfer方法的区别是tryTransfer方法无论消费者是否接收,方法立即返回,而transfer方法是必须等到消费者消费了才返回)和transfer(如果当前有消费者正在等待接收元素(消费者使用take()方法或带时间限制的poll()方法时),transfer方法可以把生产者传入的元素立刻transfer(传输)给消费者。如果没有消费者在等待接收元素,transfer方法会将元素存放在队列的tail节点,并等到该元素被消费者消费了才返回)方法

7、LinkedBlockingDeque: 一个由链表结构组成的双向阻塞队列。是一个由链表结构组成的双向阻塞队列,即可以从队列的两端插入和移除元素。双向队列因为多了一个操作队列的入口,在多线程同时入队时,也就减少了一半的竞争。相比于其他阻塞队列,LinkedBlockingDeque多了addFirst、addLast、peekFirst、peekLast等方法,以first结尾的方法,表示插入、获取获移除双端队列的第一个元素。以last结尾的方法,表示插入、获取获移除双端队列的最后一个元素。

 

拒绝策略选择

ThreadPoolExecutor.AbortPolicy: 丢弃任务并抛出RejectedExecutionException异常。 (默认)
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

说明:Executors 各个方法的弊端:
1)newFixedThreadPool 和 newSingleThreadExecutor:
主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至 OOM。队列设置大小为Integer.MAX_VALUE

2)newCachedThreadPool 和 newScheduledThreadPool:
主要问题是线程数最大数是 Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至 OOM。

Executors

Executors提供的几种创建线程池的方法

        Executors.newCachedThreadPool();
        Executors.newFixedThreadPool(4);
        Executors.newSingleThreadExecutor();
        Executors.newSingleThreadScheduledExecutor();
        Executors.newScheduledThreadPool(4);
        Executors.newWorkStealingPool();

1、newCachedThreadPool:不限制线程数量的线程池,线程数量大小和操作系统相关

具有以下特征:

(1)线程池中数量没有固定,可达到最大值(Interger. MAX_VALUE) 

(2)线程池中的线程可进行缓存重复利用和回收(回收默认时间为1分钟) 

(3)当线程池中,没有可用线程,会重新创建一个线程

(4)使用的SynchronousQueue队列

 

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

  创建方式: Executors.newCachedThreadPool();

 

2、newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。
线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

特征: 
(1)线程池中的线程处于一定的量,可以很好的控制线程的并发量 

(2)线程可以重复被使用,在显式关闭之前,都将一直存在 

(3)超出一定量的线程被提交时候需在队列中等待

(4)使用的LinkedBlockingQeque,创建时候使用的是new LinkedBlockingQeque(Integer.MAX_VALUE),所以队列是无限大的

创建方式: 
(1)Executors.newFixedThreadPool(int nThreads);//nThreads为线程的数量 
(2)Executors.newFixedThreadPool(int nThreads,ThreadFactory threadFactory);//nThreads为线程的数量,threadFactory创建线程的工厂方式

创建源码:

   public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

  

3、newSingleThreadExecutor :创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

特征: 
(1)线程池中最多执行1个线程,之后提交的线程活动将会排在队列中以此执行

(2)使用的是 LinkedBlockingQueue

创建方式: 
(1)Executors.newSingleThreadExecutor() ; 
(2)Executors.newSingleThreadExecutor(ThreadFactory threadFactory);// threadFactory创建线程的工厂方式

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

  

4、newSingleThreadScheduledExecutor创建一个单线程的线程调度器。这个调度器只有一个线程在工作

特征: 
(1)调度器的线程池中最多执行1个线程,之后提交的线程活动将会排在队列中以此执行

(2)可定时或者延迟执行线程活动

(2)使用的是 DelayedWorkQueue

创建方式: 
(1)Executors.newSingleThreadScheduledExecutor() ; 

 

    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }

  

5、newScheduledThreadPool  创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。

特征: 
(1)线程池中具有指定数量的线程,即便是空线程也将保留 
(2)可定时或者延迟执行线程活动

创建方式: 
(1)Executors.newScheduledThreadPool(int corePoolSize);// corePoolSize线程的个数 
(2)newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory);// corePoolSize线程的个数,threadFactory创建线程的工厂

    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

  

6、newWorkStealingPool:这个是 JDK1.8 版本加入的一种线程池,stealing 翻译为抢断、窃取的意思,它实现的一个线程池和上面4种都不一样,用的是 ForkJoinPool 类

 

    /**
     * Creates a thread pool that maintains enough threads to support
     * the given parallelism level, and may use multiple queues to
     * reduce contention. The parallelism level corresponds to the
     * maximum number of threads actively engaged in, or available to
     * engage in, task processing. The actual number of threads may
     * grow and shrink dynamically. A work-stealing pool makes no
     * guarantees about the order in which submitted tasks are
     * executed.
     *
     * @param parallelism the targeted parallelism level
     * @return the newly created thread pool
     * @throws IllegalArgumentException if {@code parallelism <= 0}
     * @since 1.8
     */
    public static ExecutorService newWorkStealingPool(int parallelism) {
        return new ForkJoinPool
            (parallelism,
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

    /**
     * Creates a work-stealing thread pool using all
     * {@link Runtime#availableProcessors available processors}
     * as its target parallelism level.
     * @return the newly created thread pool
     * @see #newWorkStealingPool(int)
     * @since 1.8
     */
    public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

  

Executors的两种创建方式,第一种初始化时候指出并行的线程数。
根据CPU的核数,创建一个相应并行量的ForkJoinPool线程池

 

posted on 2020-06-04 15:57  魅力峰值  阅读(284)  评论(0编辑  收藏  举报