关于java:线程池原理和实现

2次阅读

共计 3336 个字符,预计需要花费 9 分钟才能阅读完成。

$1. 概述

线程池产生背景:高并发我的项目中常常须要同时启用大量线程,因而须要创立大量线程,而频繁的创立新线程和杀死旧线程将会大大拖慢 CPU 的性能,因而利用线程池一次性初始化若干线程,应用时从池中弹出线程,执行完线程池再予以回收

线程池的工作流程:次要是管制运行的线程数量,解决过程中将工作放入队列,而后在线程创立后启动这些工作,如果线程数量超过了最大数量,超出数量的线程排队等待,等其余线程执行结束,再从队列中取出工作执行

线程池的次要特点:实现线程复用、管制最大并发数;可能系统地治理线程

线程池的劣势

  • 升高资源耗费,通过反复利用已创立的线程升高线程频繁创立和销毁的损耗
  • 进步响应速度,当工作达到时,工作能够不须要期待线程创立就能立刻执行
  • 进步线程的可管理性,线程池能够对线程进行对立的调配调度、调优以及监控

$2. 线程池的实现形式

2.1 通过 Executors 工具类

  • Executors.newFixedThreadPool(int nThreads):固定线程数量线程池
// 源码  
public static ExecutorService newFixedThreadPool(int nThreads) {  
 return new ThreadPoolExecutor(nThreads, nThreads,  
                               0L, TimeUnit.MILLISECONDS,  
                               new LinkedBlockingQueue<Runnable\>());  
}
  • Executors.newSingleThreadExecutor():单线程线程池

// 源码  
public static ExecutorService newSingleThreadExecutor() {  
 return new FinalizableDelegatedExecutorService  
 (new ThreadPoolExecutor(1, 1,  
                         0L, TimeUnit.MILLISECONDS,  
                         new LinkedBlockingQueue<Runnable\>()));  
}
  • Executors.newCachedThreadExecutor():可扩容线程池,实践上反对 Integer.MAX_VALUE 条线程
// 源码
public static ExecutorService newCachedThreadPool() {  
 return new ThreadPoolExecutor(0, Integer.MAX\_VALUE,  
                               60L, TimeUnit.SECONDS,  
                               new SynchronousQueue<Runnable\>());  
}

本质上,这三种线程池尽管各有特点,但底层实现的都是 ThreadPoolExecutor 类,也即最正统的线程池,线程池本池☺

  • 理论应用
// 应用案例
import java.util.concurrent.Executors;

public class NewFixedThreadPoolDemo {public static void main(String[] args) {ExecutorService threadPool = Executors.newFixedThreadPool(5);
        // ExecutorService threadPool = Executors.newSingleThreadExecutor();
        // ExecutorService threadPool = Executors.newCachedThreadExecutor();
        
        
        for(int i=0; i<10; i++){threadPool.execute(()-> System.out.println(Thread.currentThread().getName() + "\t 办理业务"));
        }
        
        threadPool.shutdown(); // 敞开资源!!}
}

2.2 通过 ThreadPoolExecutor[线程池本池!用它!用它! 用它!]

WHY?(谁说的不能用 Executors?)

  • 马云曰:我说的!(阿里编程标准明确示意不倡议外部应用 Executors 工具类实现线程池)
  • fixThreadPool 和 SingleThreadPool 设置的工作申请队列为 Integer.MAX_VALUE,可能会沉积大量的申请,从而导致 OOM
  • CachedThreadPool 和 ScheduledThreadPool 容许创立的线程数量为 Integer.MAX_VALUE, 可能会创立大量线程,从而导致 OOM
// 代码实现
import java.util.concurrent.*;
public class ThreadPoolExecutorDemo {public static void main(String[] args) {
        ExecutorService threadPool = new ThreadPoolExecutor(2,
                5,
                2L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardPolicy());

        for(int i=1; i<=10; i++){
            final int temp = i;
            threadPool.execute(()-> System.out.println(Thread.currentThread().getName() + "\t 办理业务" + temp));
        }
        threadPool.shutdown();}
}

参数解析

  • corePoolSize:线程池中的常驻外围线程数
  • maximumPoolSize:线程池中可能包容同时执行的最大线程数,该值必须大于等于 1
  • keepAliveTime:多余的闲暇线程的存货工夫,以后池中线程数量大于 corePoolSize 时,当闲暇线程的闲暇工夫达到 keepAliveTime,多余的线程会被销毁直到剩下 corePoolSize 个
  • unit:keepAliveTime的单位
  • workQueue:工作队列,被提交但尚未被执行的工作 — 设想银行的等待区
  • threadFactory:示意生成线程池中工作线程的线程工厂,用于创立线程,个别应用默认即可
  • handler:回绝策略,示意当线程池和队列都满了,线程池采取何种策略来拒绝请求执行的 Runnable 工作

$3. 线程池工作原理

talk is cheap, show me the diagram

线程池个别工夫都只会开启外围线程数量的线程,而当工作队列满了之后,线程池会启用非核心线程池区(这里形容只是逻辑分区,实际上线程之间都是等同位置),创立线程并执行工作;而当工作队列中工作变少,有些线程开始闲置,闲置工夫达到设置的 keepAliveTime 后,线程池会登记回收这些闲置线程,直到线程数量复原外围线程数

  • 一个线程池可能并发解决的最大工作数 = maximumPoolSize + workQueue 设置的长度

$4. 回绝策略 (渣男[女] 必备)

共有四种回绝策略,以 2.2 中的代码为准,即设置外围线程数为 2、最大线程数为 5、工作队列容量为 3、工作数为 10;见四种策略别离的运行后果如下

  • AbortPolicy:当无奈执行工作时,间接抛出 RejectedExecutionException 中断程序

  • CallerRunsPolicy:调用者运行机制,该策略不会摈弃工作,也不会抛出异样,而是将无奈执行的工作返还给调用者执行,这里因为是 main 线程调用的,因而返还给 main 线程执行工作。如下图,工作 9 被返还给 main 线程执行了,这过程的工夫内线程池可能曾经执行完工作 1 了,工作队列从而空了一个地位,工作 10 便间接进入工作队列没有返还给 main 线程。在保障工作完全性的状况下,该策略是惟一策略

  • DiscardOldestPolicy:摈弃队列中期待最久的工作,而后把当前任务退出到队列中尝试再次提交当前任务

  • DiscardPolicy:该策略会抛弃无奈解决的工作,不做任何解决也不抛异样,如果容许工作失落,这是最好的一种策略

REFERENCE

尚硅谷周阳老师 JUC 课程:https://www.bilibili.com/vide…

正文完
 0