zoukankan      html  css  js  c++  java
  • 线程池

    概念

    简介

    线程池就是先创建一些线程,他们的集合称为线程池。

    使用线程池,可以很好的提高性能,线程池再系统启动时即创建大量空闲的线程,程序奖一个任务传给线程池,线程池就会启动1条线程来执行此任务,执行结束后,线程不会死亡,而是再次返回线程池成为空闲状态,等待下一任务。

     

    工作机制

    1)在线程池的编程模式下,任务是提交给整个线程池,而不是直接交给某个线程,线程池在拿到任务后就在内部寻找空闲的线程,如果有就将任务交给空闲的线程。

    2)一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务。

     

    使用线程池的原因

    多线程运行时,系统不断的启动和关闭线程,成本非常高,会过度消耗系统资源,以及过度切换线程的危险,从而可能导致系统资源的崩溃。

     

    常见线程池

    SingleThreadExecutor

    只有一条线程来执行任务,适用于有顺序的任务的应用场景

    底层实现

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

    程序实验

     private static void SingleThreadExecutor() {
         // 一池 仅有 1个线程
         ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
         // 模拟10个用户请求线程
         try {
             for (int i = 1; i <= 10; i++) {
                 singleThreadExecutor.execute(() -> {
                     System.out.println(Thread.currentThread().getName() + "	 处理请求");
                 });
             }
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             singleThreadExecutor.shutdown();
         }
         // 程序运行结果
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
     }

    线程池只有1个线程,所以仅有1个线程执行任务

     

    CachedThreadPool

    可缓存的线程池,该线程池中没有核心线程,非核心线程数量为Integer.max_value,就是无限大,当有需要时创建线程来执行任务,没有需要时则回收线程,适用于耗时少,任务量大的情况

    底层代码

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

    程序实验:

     private static void CachedThreadPool() {
         // 一池 n 个线程
         ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
         try {
             for (int i = 1; i <= 10; i++) {
                 cachedThreadPool.execute(() -> {
                     System.out.println(Thread.currentThread().getName() + "	 处理请求");
                 });
             }
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             cachedThreadPool.shutdown();
         }
         // 程序运行结果
         // pool-1-thread-1  处理请求
         // pool-1-thread-2  处理请求
         // pool-1-thread-3  处理请求
         // pool-1-thread-4  处理请求
         // pool-1-thread-5  处理请求
         // pool-1-thread-6  处理请求
         // pool-1-thread-7  处理请求
         // pool-1-thread-8  处理请求
         // pool-1-thread-10 处理请求
         // pool-1-thread-9  处理请求
     }

     

    FixedThreadPool

    定长的线程池,有核心线程,核心线程的数量即为最大的线程数量,没有非核心线程。

    底层代码

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

    程序实验:

     private static void FixedThreadPool() {
         // 一池5个线程
         ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
     ​
         // 模拟10个用户请求线程
         try {
             for (int i = 1; i <= 10; i++) {
                 fixedThreadPool.execute(() -> {
                     System.out.println(Thread.currentThread().getName() + "	 处理请求");
                 });
             }
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             fixedThreadPool.shutdown();
         }
         // 程序运行结果
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-2  处理请求
         // pool-1-thread-3  处理请求
         // pool-1-thread-4  处理请求
         // pool-1-thread-5  处理请求
     }

    结果分析:可以一个线程处理多个任务,但是总线程数不会改变。

     

    ScheduledThreadPool

    周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大,适用于执行周期的任务。

    底层代码

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

    程序实验:

     private static void ScheduledThreadPool() {
         ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
         try {
             for (int i = 1; i <= 10; i++) {
                 scheduledThreadPool.execute(() -> {
                     System.out.println(Thread.currentThread().getName() + "	 处理请求");
                 });
             }
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             scheduledThreadPool.shutdown();
         }
         // 程序运行结果
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
         // pool-1-thread-1  处理请求
     }

     

    7大核心参数

    简介

    出自 ThreadPoolExecutor 的一个构造方法

     

     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.acc = System.getSecurityManager() == null ?
                 null :
                 AccessController.getContext();
         this.corePoolSize = corePoolSize;
         this.maximumPoolSize = maximumPoolSize;
         this.workQueue = workQueue;
         this.keepAliveTime = unit.toNanos(keepAliveTime);
         this.threadFactory = threadFactory;
         this.handler = handler;
     }

    corePoolSize

    线程池中常驻核心线程数

    maximumPoolSize

    线程池可容纳同时执行的最大线程数,值必须 >= 1

    keepAliveTime

    多余的空闲线程存活时间。当前线程池数量超过corePoolSize时,当空闲时间到达keepAliveTime值时,多余空闲线程会被销毁直至只剩下corePoolSize为止

    unit

    keepAliveTime的时间单位

    workQueue

    任务队列,被提交但尚未执行的任务

    threadFactory

    表示生成线程池中的工作线程的线程工厂,用于创建线程,一般为默认的线程工厂即可

    handler

    拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时如何来拒绝请求的Runable的策略

     

    线程池工作原理

    原理图

    img

    img

    文字解释

    当调用线程池的 execute() 方法时,线程池会做出以下判断:

    1)如果 当前运行的线程数 小于 线程池的核心线程数,那么马上创建线程完成此任务

    2)如果 运行的线程数 大于等于 线程池的核心线程数,那么将线程放进任务队列等待

    3)如果 此时任务队列已满,且正在运行的线程数 小于 最大线程数,立即创建非核心线程执行这个任务

    4)如果 此时任务队列已满,且正在运行的线程数 等于 最大线程数,啧线程池会启动饱和和 拒绝策略 来执行

     

    4种拒绝策略

    这4种拒绝策略都实现了 RejectedExecutionHandler

    AbortPolicy(默认)

    直接抛出RejectedExecutionException,异常阻止系统正常运行

    CallerRunsPolicy

    "调用者运行",一种调节机制,该策略既不会抛异常,又不会抛弃任务,而是将某些任务回退刀调用者,从而降低新任务的流量

    DiscardOldestPolicy

    抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务

    DiscardPolicy

    直接丢弃任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种方案

     

    阿里规范

    1)

    2)

     

     

  • 相关阅读:
    杭电2081
    杭电2083
    杭电2084
    3/5/2014 cfb 小心
    116
    uva10003
    10815
    127
    674
    uva 13598
  • 原文地址:https://www.cnblogs.com/kzyuan/p/14470832.html
Copyright © 2011-2022 走看看