线程池:就是一个管理线程的池子。

优点:

  • 它帮我们管理线程,避免增加创建线程和销毁线程的资源损耗。因为线程其实也是一个对象,创建一个对象,需要经过类加载过程,销毁一个对象,需要走GC垃圾回收流程,都是需要资源开销的。
  • 提高响应速度。 如果任务到达了,相对于从线程池拿线程,重新去创建一条线程执行,速度肯定慢很多。
  • 重复利用。 线程用完,再放回池子,可以达到重复利用的效果,节省资源。

一、线程池的创建

线程池可以通过ThreadPoolExecutor来创建

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long
keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
//corePoolSize: 线程池核心线程数最大值
//maximumPoolSize: 线程池最大线程数大小
//keepAliveTime: 线程池中非核心线程空闲的存活时间大小
//unit: 线程空闲存活时间单位
//workQueue: 存放任务的阻塞队列
//threadFactory: 用于设置创建线程的工厂,可以给创建的线程设置有意义的名字,可方便排查问题。
//handler: 线城池的饱和策略事件,主要有四种类型。

  二、线程池处理流程

1,首先线程池判断基本线程池是否已满(< corePoolSize ?)?没满,创建一个工作线程来执行任务。满了,则进入下个流程。

2,其次线程池判断阻塞队列是否已满?没满,则将新提交的任务存储在阻塞队列里。满了,则进入下个流程。

3,最后线程池判断整个线程池是否已满(< maximumPoolSize ?)?没满,则创建一个新的工作线程来执行任务,满了,则交给饱和策略来处理这个任务。

三、线程池的阻塞队列

线程池阻塞队列:1、有界阻塞队列          2、无界阻塞队列             3、同步移交阻塞队列

public class QueueTest {

    @Test
public void arrayBlockingQueue() throws InterruptedException {
/**
* 基于数组的有界阻塞队列,队列容量为10
*/
ArrayBlockingQueue queue =
new ArrayBlockingQueue<Integer>(10); // 循环向队列添加元素
for (int i = 0; i < 20; i++) {
queue.put(i);
System.out.println("向队列中添加值:" + i);
}
} @Test
public void linkedBlockingQueue() throws InterruptedException {
/**
* 基于链表的有界/无界阻塞队列,队列容量为10
*/
LinkedBlockingQueue queue =
new LinkedBlockingQueue<Integer>(); // 循环向队列添加元素
for (int i = 0; i < 20; i++) {
queue.put(i);
System.out.println("向队列中添加值:" + i);
}
} @Test
public void test() throws InterruptedException {
/**
* 同步移交阻塞队列
*/
SynchronousQueue queue = new SynchronousQueue<Integer>(); // 插入值
new Thread(() -> {
try {
queue.put(1);
System.out.println("插入成功");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start(); // 删除值
new Thread(() -> {
try {
queue.take();
System.out.println("删除成功");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start(); Thread.sleep(1000L * 60);
} }

  四、线程池饱和策略

  1. Caller-runs调用者运行策略,即该线程的执行有调用的这个线程来执行,调用的线程会暂停原来的任务,转而去执行该任务,该任务执行完成后继续执行原来的任务
  2. AbortPolicy终止策略(系统默认), 该策略保证在线程池满的情况下任何试图提交任务到该线程池的线程的线程均会抛出,RejectedExecutionException,该异常导致调用线程的终止。但这种异常时可以捕获的(非检查型异常)。
  3. DiscardPolicy抛弃策略,该策略保证任何试图向满的线程池提交任务时,该任务的提交会立即返回,任务不会被提交,并且不会抛出任何形式的异常。
  4. DiscardOldestPolicy抛弃旧任务策略,这种模式下,将会抛弃下一个将要执行的任务,然后把刚提交的任务添加到任务队列,等待执行。

  五、线程池的常用线程池

  1. newCachedThreadPool  (创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。)

    public static ExecutorService newCachedThreadPool(){
    return new ThreadPoolExecutor(
    0, // corePoolSoze == 0
    Integer.MAX_VALUE, // maximumPoolSize 非常大
    60L, // 空闲判定是60 秒
    TimeUnit.SECONDS,
    // 神奇的无存储空间阻塞队列,每个 put 必须要等待一个 take
    new SynchronousQueue<Runnable>()
    );
    }

      

  2. newFixedThreadPool    (创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。)

    public static ExecutorService newFixedThreadPool(int nThreads){
    return new ThreadPoolExecutor(
    nThreads, // corePoolSize
    nThreads, // maximumPoolSize == corePoolSize
    0L, // 空闲时间限制是 0
    TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<Runnable>() // 无界阻塞队列
    );
    }

      

  3. newSingleThreadPool     (创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。)

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

      

  4. newScheduleThreadPool      (创建一个定长的线程池,而且支持定时的以及周期性的任务执行,支持定时及周期性任务执行。)

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
    }

      

    六、向线程池提交任务

    提交任务有两种方式:1、有返回结果-sunmit               2、无返回结果-execute

public class RunTest {

    @Test
public void submitTest()
throws ExecutionException, InterruptedException { // 创建线程池
ExecutorService threadPool =
Executors.newCachedThreadPool(); /**
* 利用submit方法提交任务,接收任务的返回结果
*/
Future<Integer> future = threadPool.submit(() -> {
Thread.sleep(1000L * 10); return 2 * 5;
}); /**
* 阻塞方法,直到任务有返回值后,才向下执行
*/
Integer num = future.get(); System.out.println("执行结果:" + num);
} @Test
public void executeTest() throws InterruptedException {
// 创建线程池
ExecutorService threadPool =
Executors.newCachedThreadPool(); /**
* 利用execute方法提交任务,没有返回结果
*/
threadPool.execute(() -> {
try {
Thread.sleep(1000L * 10);
} catch (InterruptedException e) {
e.printStackTrace();
} Integer num = 2 * 5;
System.out.println("执行结果:" + num);
}); Thread.sleep(1000L * 1000);
} }

  关于线程池五种状态:

线程池的5种状态:RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED.

1、RUNNING

(1). 状态说明:线程池处在RUNNING状态时,能够接收新任务,以及对已添加的任务进行处理。

(2). 状态切换:线程池的初始化状态是RUNNING。换句话说,线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0!

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

2、 SHUTDOWN

(1). 状态说明:线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务。

(2). 状态切换:调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN。

3、STOP

(1). 状态说明:线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。

(2). 状态切换:调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) -> STOP。

4、TIDYING

(1). 状态说明:当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态。

当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;

可以通过重载terminated()函数来实现。

(2). 状态切换:当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。

当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。

5、 TERMINATED

(1). 状态说明:线程池彻底终止,就变成TERMINATED状态。

(2). 状态切换:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。

最后实践Springboot中线程池的使用

@Configuration
@EnableAsync
public class ExecutorConfig { @Bean("exportServiceExecutor")
public Executor exportServiceExecutor(){
//创建线程池
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程数量:当前机器核心数
executor.setCorePoolSize (
Runtime.getRuntime().availableProcessors());
//最大线程数
executor.setMaxPoolSize(
Runtime.getRuntime().availableProcessors() * 2);
//队列大小
executor.setQueueCapacity(Integer.MAX_VALUE);
//线程池中线程名前缀
executor.setThreadNamePrefix("export-");
//线程池阻塞策略-拒绝策略:直接拒绝
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.AbortPolicy());
return executor;
}
}

  

@Async("exportServiceExecutor") //指定线程池
public void executorTest(){
System.out.println("测试线程");
}

  

对于线程池ThreadPool的学习总结的更多相关文章

  1. 关于线程池ThreadPool的学习

    学习重点ThreadPool.SetMinThreads(out workerThreads, out completionPortThreads).这是整个线程池的关键.  而ThreadPool. ...

  2. java核心知识点学习----重点学习线程池ThreadPool

    线程池是多线程学习中需要重点掌握的. 系统启动一个新线程的成本是比较高的,因为它涉及与操作系统交互.在这种情形下,使用线程池可以很好的提高性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考 ...

  3. C#多线程学习 之 线程池[ThreadPool](转)

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  4. C#多线程学习 之 线程池[ThreadPool]

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  5. [转]C#多线程学习 之 线程池[ThreadPool]

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  6. 多线程系列 线程池ThreadPool

    上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...

  7. 多线程系列(2)线程池ThreadPool

    上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...

  8. 线程池ThreadPool实战

    线程池ThreadPool 线程池概念 常用线程池和方法 1.测试线程类 2.newFixedThreadPool固定线程池 3.newSingleThreadExecutor单线程池 4.newCa ...

  9. 线程池ThreadPool的初探

    一.线程池的适用范围 在日常使用多线程开发的时候,一般都构造一个Thread示例,然后调用Start使之执行.如果一个线程它大部分时间花费在等待某个事件响应的发生然后才予以响应:或者如果在一定期间内重 ...

随机推荐

  1. Asp.Net实现局部刷新,ScriptManager和UpdatePanel控件的使用

    <asp:CheckBoxList ID="LimitCollegeNo" runat="server" CellPadding="5" ...

  2. 理解Margin边距塌陷与box-sizing的问题

    父与子塌陷问题 子盒子与父盒子相互影响,margin值会重叠,谁大听谁的 运行结果: box-sizing box-sizing 原始属性值: content-box,该属性对于盒子尺寸来说,并不会让 ...

  3. airtest操作夜神模拟器adb冲突解决办法

    首先看错误日志明显是adb之间版本不对应互相干掉对方 第一步 去aritestIde所在目录\AirtestIDE\airtest\core\android\static\adb\windows 第二 ...

  4. 使用Node.js给图片加水印的方法

    一.准备工作: 首先,确保你本地已经安装好了node环境. 然后,我们进行图像编辑操作需要用到一个Node.js的库:images. 这个库的地址是:https://github.com/zhangy ...

  5. 小白:String函数总结

    string.h函数: 1.strlen 数出字符串存在多少字符: 2.strcmp 比较两个字符串,若相等返回0不相等返回1 3.strcpy(char *restrict dst,const ch ...

  6. U138097 小鱼吃大鱼 埃氏筛

    题目描述 小P同学在养殖一种非常凶狠的鱼,而且与其他鱼类不同,这种鱼越大越温顺,反而小鱼最凶残.当两条鱼相遇时, 小鱼会不断撕咬大鱼,每一口都咬下与它自身等重的肉(小鱼保持体重不变),直到大鱼的体重小 ...

  7. HTTP协议(2)

    HTTP协议主要是有HTTP请求报文和HTTP响应报文组成的. HTTP请求报文主要分为四个部分: 第一部分:请求行.独占一行,由请求方法.请求url以及协议/版本组成: 第二部分:请求头,第二行到第 ...

  8. Python爬虫之多线程

    详情点我跳转 关注公众号"轻松学编程"了解更多. 多线程 在介绍Python中的线程之前,先明确一个问题,Python中的多线程是假的多线程! 为什么这么说,我们先明确一个概念,全 ...

  9. vim编辑器使用简介

    使用格式 vim [option] /path/to/somefile ... option: -o水平分割 -O垂直分割 +打开后在最后一行 +Num打开后在地Num行,加号与Num之间不能有空格 ...

  10. 直播平台搭建之音视频开发:认识主流视频编码技术H.264

    H.264简介 什么是H.264?H.264是一种高性能的视频编解码技术.目前国际上制定视频编解码技术的组织有两个,一个是"国际电联",它制定的标准有H.261.H.263.H.2 ...