创建线程池可以分为三种方式:

1. 通过ThreadPoolExecutor的构造方法,创建ThreadPoolExecutor的对象,即一个线程池对象;

此构造方法,一共7个参数,5个必须参数,2个带有默认值的参数;详细后面说;

传送:https://www.cnblogs.com/mussessein/p/11654022.html

2. 通过Executors返回的线程池对象;

这种方法创建的常用线程池为4种,还可以创建ForkJoinPool对象;

可以说是封装好的方法,通过Executors的4种常用静态方法,返回4种已经封装好的ThreadPoolExecutor线程池对象;

传送:https://www.cnblogs.com/mussessein/p/11654120.html

3. ForkJoinPool并发框架

将一个大任务拆分成多个小任务后,使用fork可以将小任务分发给其他线程同时处理,使用join可以将多个线程处理的结果进行汇总;这实际上就是分治思想。

为什么要使用线程池:

使用线程池的好处

  1. 降低资源消耗。重复利用已创建线程,降低线程创建与销毁的资源消耗。

  2. 提高响应效率。任务到达时,不需等待创建线程就能立即执行。

  3. 提高线程可管理性。

  4. 防止服务器过载。内存溢出、CPU耗尽。

进入正题:

ThreadPoolExecutor

尽量使用此类创建线程池,而非Executors创建;使用此方法,更明确线程池的运行规则,规避资源耗尽的风险

先说一下线程池的流程:

  1. 线程先进入核心池运行;

  2. 核心池满了,进队列等待;

  3. 队列满了,就创建新线程,直到最大线程数满了,之外的线程就被拒绝rejected;

在最后,会有代码演示,整个线程池的流程,很详细!

看构造器:

// 七参构造器,前五个参数必须
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory, //可以不写
RejectedExecutionHandler handler) // 可以不写

ThreadPoolExecutor的四种构造器的各项参数:

  • corePoolSize:核心池的大小,并非线程的最大数量

    • maximumPoolSize > corePoolSize

    • 在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中

  • maximumPoolSize:线程池的最大线程数,表示线程池中最多能创建多少个线程

  • keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止

    • 默认:只有线程池内线程数大于corePoolSize的线程,keepAliveTime才会对其计时

    • 当一个线程的空闲时间大于keepAliveTime,则会被终止

    • 如果调用了allowCoreThreadTimeOut(boolean),线程池内线程数小于corePoolSize,keepAliveTime也会起作用

  • unit:参数keepAliveTime的时间单位(七种单位)

    TimeUnit.DAYS;              //天
    TimeUnit.HOURS; //小时
    TimeUnit.MINUTES; //分钟
    TimeUnit.SECONDS; //秒
    TimeUnit.MILLISECONDS; //毫秒
    TimeUnit.MICROSECONDS; //微妙
    TimeUnit.NANOSECONDS; //纳秒
  • workQueue:选择一个阻塞队列

    LinkedBlockingQueue;    // 常用,无界阻塞队列,不传值默认为Integer.MAX_VALUE,容易内存耗尽
    SynchronousQueue;
    ArrayBlockingQueue;
    PriorityBlockingQueue // 优先队列
  • threadFactory:线程工厂,主要用来创建线程。如果不传此参数,默认:Executors.defaultThreadFactory()

  • RejectedExecutionHandler handler:表示当拒绝处理任务时的策略,有以下四种取值:

    如果不传此参数,默认:ThreadPoolExecutor.AbortPolicy

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

  可以自行实现implements RejectedExecutionHandler接口,来自定义线程被线程池拒绝之后的操作:后面有演示;

ThreadPoolExecutor的重要方法:

  • execute(Runnable command)

    通过这个方法可以向线程池提交一个任务,交由线程池去执行

    此方法在执行的时候,会判断当前线程数是否大于corePoolSize

    如果当前线程数大于corePoolSize,并且,当前线程池处于RUNNING状态,则将此任务加入任务缓冲队列

  • submit()

    内部调用execute()方法

    这个方法也是用来向线程池提交任务的,但是它和execute()方法不同

    它能够返回任务执行的结果,利用了Future来获取任务执行结果

  • shutdown()

    关闭线程池,此时线程池不能够接受新的任务,它会等待所有任务执行完毕

  • shutdownNow()

    关闭线程池,线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务

演示线程池流程:

public class Task implements Runnable {
private String name;
public Task(String name) {
this.name = name;
}
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return this.name;
}
}
/**
* 重写RejectedExecutionHandler
* 自定义线程池拒绝线程之后的行为
*/
public class MyRejectedHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("Rejected:"+r.toString());
}
} /**
* ThreadPoolExecutor的使用实例。
* 四个必要参数,
* RejectedHandler为自己定义的RejectedExecutionHandler实现类
* 线程流程:
* 1.进入核心池,核心池满了,之后线程,进入队列
* 2.队列满了,继续创建线程,直到最大线程数
* 3.最大线程数已满,拒绝后续线程
*/
public class ThreadPoolDemo { public static void main(String[] args) {
/**
* 设置线程池参数:
* 核心线程:2
* 最大线程:3
* 阻塞队列大小:5
* 拒绝策略:自定义
*/
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2, 3, 2000,
TimeUnit.MILLISECONDS, new ArrayBlockingQueue(5), new MyRejectedHandler()); // 启动一个主线程,内部启动10个子线程添加进线程池
Runnable runTask = () -> { for (int i = 0; i < 10; i++) {
String name = "Task_" + i;
Task task = new Task(name);
try {
/**
* 每次添加线程到线程池,都打印线程池的内部情况
*/
threadPoolExecutor.execute(task);
System.out.println("PoolSize: " + threadPoolExecutor.getPoolSize() +
",Queue" + threadPoolExecutor.getQueue());
System.out.println();
} catch (Exception e) {
System.out.println("Refused:" + name);
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Thread thread = new Thread(runTask);
thread.start();
}
}

运行结果:

PoolSize: 1,Queue[]
PoolSize: 2,Queue[]
// 到这里,核心池满了,之后线程,进入队列
PoolSize: 2,Queue[Task_2]
PoolSize: 2,Queue[Task_2, Task_3]
PoolSize: 2,Queue[Task_2, Task_3, Task_4]
PoolSize: 2,Queue[Task_2, Task_3, Task_4, Task_5]
PoolSize: 2,Queue[Task_2, Task_3, Task_4, Task_5, Task_6]
// 队列满了,继续创建线程到线程池,这一个多余的线程会在等待,并倒计时keepAliveTime
PoolSize: 3,Queue[Task_2, Task_3, Task_4, Task_5, Task_6]
// 最大线程数已满,拒绝后续线程
Rejected:Task_8
PoolSize: 3,Queue[Task_2, Task_3, Task_4, Task_5, Task_6]
Rejected:Task_9
PoolSize: 3,Queue[Task_2, Task_3, Task_4, Task_5, Task_6]

执行execute()方法和submit()方法的区别

(1)execute() 方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;

(2)submit()方法用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且可以通过future的get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用 get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。

【JUC】6.线程池—ThreadPoolExecutor的更多相关文章

  1. 硬核干货:4W字从源码上分析JUC线程池ThreadPoolExecutor的实现原理

    前提 很早之前就打算看一次JUC线程池ThreadPoolExecutor的源码实现,由于近段时间比较忙,一直没有时间整理出源码分析的文章.之前在分析扩展线程池实现可回调的Future时候曾经提到并发 ...

  2. java面试总躲不过的并发(一): 线程池ThreadPoolExecutor基础梳理

    本文核心:线程池ThreadPoolExecutor基础梳理 一.实现多线程的方式 1.继承Thread类,重写其run方法 2.实现Runnable接口,实现run方法 3.实现Callable接口 ...

  3. Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理

    相关文章目录: Java线程池ThreadPoolExecutor使用和分析(一) Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理 Java线程池Thr ...

  4. Java线程池ThreadPoolExecutor使用和分析(一)

    相关文章目录: Java线程池ThreadPoolExecutor使用和分析(一) Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理 Java线程池Thr ...

  5. 线程池 ThreadPoolExecutor 原理及源码笔记

    前言 前面在学习 JUC 源码时,很多代码举例中都使用了线程池 ThreadPoolExecutor,并且在工作中也经常用到线程池,所以现在就一步一步看看,线程池的源码,了解其背后的核心原理. 公众号 ...

  6. 细说JUC的线程池架构

    前言 线程的创建是需要JVM和OS(操作系统)相互配合的,一次的创建要花费许多的资源. 1.首先,JVM要为该线程分配堆栈和初始化大量内存块,栈内存至少是1MB. 2.其次便是要进行系统的调用,在OS ...

  7. java线程池ThreadPoolExecutor使用简介

    一.简介线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为:ThreadPoolExecutor(int corePoolSize, int m ...

  8. 线程池ThreadPoolExecutor

    线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为: ThreadPoolExecutor(int corePoolSize, int maxi ...

  9. 关于线程池ThreadPoolExecutor使用总结

    本文引用自: http://blog.chinaunix.net/uid-20577907-id-3519578.html 一.简介 线程池类为 java.util.concurrent.Thread ...

  10. [转] 引用 Java自带的线程池ThreadPoolExecutor详细介绍说明和实例应用

    PS: Spring ThreadPoolTaskExecutor vs Java Executorservice cachedthreadpool 引用 [轰隆隆] 的 Java自带的线程池Thre ...

随机推荐

  1. Qt开发经验小技巧1-10

    当编译发现大量错误的时候,从第一个看起,一个一个的解决,不要急着去看下一个错误,往往后面的错误都是由于前面的错误引起的,第一个解决后很可能都解决了. 定时器是个好东西,学会好使用它,有时候用QTime ...

  2. [LeetCode] 97. Interleaving String 交织相错的字符串

    Given s1, s2, s3, find whether s3 is formed by the interleaving of s1and s2. Example 1: Input: s1 = ...

  3. [LeetCode] 217. Contains Duplicate 包含重复元素

    Given an array of integers, find if the array contains any duplicates. Your function should return t ...

  4. LeetCode:复原IP地址【93】

    LeetCode:复原IP地址[93] 题目描述 给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式. 示例: 输入: "25525511135" 输出: [&qu ...

  5. java面试 (六)

    1 String.split(String regex), 传入的参数是正则表达式,有一些特殊字符(比如.[]()\| 等)需要转义. 2  关于枚举类型,一般用作常量,理想情况下,枚举中的属性字段是 ...

  6. Python和Java、PHP、C、C#、C++等其他语言的对比?

    1111 1.C语言,它既有高级语言的特点,又具有汇编语言的特点,它是结构式语言.C语言应用指针:可以直接进行靠近硬件的操作,但是C的指针操作不做保护,也给它带来了很多不安全的因素.C++在这方面做了 ...

  7. SecureCRT字体、界面优化

    SecureCRT字体.界面优化 本文是secureCRT的第三篇博文,也是目前secureCRT优化的最终篇.首次使用该软件时候.应该会设置字体和编码,接下来,将演示如何设置. 1. 字体.编码设置 ...

  8. tetetet

    http://www.wuwenhui.cn/2623.html http://www.360doc.com/content/16/1104/09/36005694_603810507.shtml

  9. [转帖]Linux教程(8)-Linux中的进程和日志㐇、

    Linux教程(8)-Linux中的进程和日志 2018-08-20 23:42:23 钱婷婷 阅读数 3554更多 分类专栏: Linux教程与操作 Linux教程与使用   版权声明:本文为博主原 ...

  10. 『Go基础』第6节 注释

    在上一节中, 我们学会了怎样写一个 Hello Go . 但是, 大家有可能还没有明白为什么那么写, 下面我们通过注释来了解一下. 注释的重要性不再过多赘述, 一段不写注释的代码读起来实在难受. 那么 ...