zoukankan      html  css  js  c++  java
  • 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线程池
  • 相关阅读:
    jquery封装的时间轴
    openlayers实现多图显示
    wms常用操作
    教你如何拔取百度地图POI兴趣点
    北京市地铁线路及站点数据
    Arcgis for js实现北京地铁的展示
    Openlayers 2.X加载高德地图
    Arcgis for js加载百度地图
    常用公共服务接口与java调用实现
    Openlayers 2.X加载天地图
  • 原文地址:https://www.cnblogs.com/mlfz/p/13044035.html
Copyright © 2011-2022 走看看