线程池 的一些事

简介: 线程池 的一些事

0f11c8b5e6424e769f9e23f7a355fe49.jpg


一、线程池

1. 线程池的好处?


创建线程:线程的本质是PCB,是内核中的数据结构。而创建线程,由内核完成 PCB 的创建,把PCB加入到调度队列中~~然后再返回给应用程序。


而加入线程池:从线程池中去线程,把线程放回到线程池,这是纯用户态实现的逻辑。


创建线程需要涉及到 用户态~内核态 之间的切换,而这种切换存在很大的开销。为了避免这种情况,引入了线程池,实现了 纯用户态 的逻辑。


1. ThreadPoolExecutor 和 Executor ?


在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。而线程池不允许使用 Executor 去创建,而要通过 ThreadPoolExecutor 方式,这一方面是由于 jdk 中  Executor  框架虽然提供了如newFixedThreadPool()、newSingleThreadExecutor()、newCachedThreadPool()等创建线程池的方法,但都有其局限性,不够灵活;另外由于前面几种方法内部也是通过ThreadPoolExecutor 方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险。


c5e502c33a80452a981722f947d14fa5.png

Executor 类 本质上是ThreadPoolExecutor 类 的封装

说白了,使用 Executor 类创建线程池与使用ThreadPoolExecutor类的区别就是使用 ThreadPoolExecutor 类可以自定义传入我们设置的线程池的参数,更加灵活。


二、构造方法:

1. ThreadPoolExecutor提供了四个构造方法:


79c45f3cd6f3496a9028672cd4932d89.png


2. 构造参数解释:


序号 名称 类型 含义
1 corePoolSize int 核心线程池大小
2 maximumPoolSize int 最大线程池大小
3 keepAliveTime long 线程最大空闲时间
4 unit TimeUnit 时间单位
5 workQueue BlockingQueue<Runnable> 线程等待队列
6 threadFactory ThreadFactory 线程创建工厂
7 handler RejectedExecutionHandler 拒绝策略


3. 线程池的执行流程

① 当加入一个新任务时,判断 当前线程数 > 核心线程数 ? 如果false,则新建线程并且执行任务。


② 如果true,则判断 任务队列是否满了? 如果false,则放到任务队列,等待核心线程处理。


③ 如果true,则判断 当前线程数>最大线程数? 如果false 则新建线程执行此任务。


④ 如果true,则执行拒绝策略


4. 几种拒绝策略


AbortPolicy         -- 抛出 RejectedExecutionException 异常。

CallerRunsPolicy    -- 让调用者处理

DiscardOldestPolicy -- 丢弃最老的任务,将新任务放到等待队列。

DiscardPolicy       -- 直接丢弃这个新任务


5. 由于参数过于复杂,我们可以通过Executors的工厂方法创建线程池


newFixedThreadPool :创建固定线程数的线程池

CachedThreadPool:创建线程数媒动态增长的线程池

SingleThreadExecutor:创建只包含单个线程的线程池

ScheduledThreadPool:设定 延迟时间后执行命令,或定期执行命令,是进阶版的 Timer

    public static void main(String[] args) {
        //创建一个固定有10个线程数的线程池
        ExecutorService executorService  = Executors.newFixedThreadPool(10);
        Runnable run = new Runnable() {
            @Override
            public void run() {
                System.out.println("good !");
            }
        };
        executorService.submit(run);
    }

三、代码简单实现


核心操作是 submit --- 将任务加入到线程池中

使用 Worker 类描述一个工作线程,使用 Runnable 或者 Callable 描述一个任务

使用一个 BlockingQueue 组织所有任务

每个Worker 县城要做的事情:不停的从 BlockingQueue 中取任务并执行

指定一下线程池中最大线程数 maxWorkerCount ,当当前线程数超过这个最大值就不再新增线程

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
public class Demo10 {
    //MyWork   负责完成组织一个线程的工作
    public static class MyWork extends Thread {
        private LinkedBlockingQueue<Runnable> queue;
        public MyWork(LinkedBlockingQueue<Runnable> queue) {
            super();
            this.queue = queue;
        }
        @Override
        public void run() {
            try {
                while (!Thread.interrupted()){
                    Runnable runnable = queue.take();
                    runnable.run();
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
    //Study.MyThreadPool 负责完成组织所有的线程
    public static class MyThreadPool {
        private int maxContain = 10;//最多开辟多少个线程
        private LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
        private List<MyWork> workList = new LinkedList<>();
        public void submit(Runnable runnable) throws InterruptedException {
            if (maxContain > queue.size()) {//如果线程数量没有达到最大则优先创建一个新线程执行任务
                MyWork work = new MyWork(queue);
                workList.add(work);
                work.start();
            }
            queue.put(runnable);
        }
    }
    public static void main(String[] args) throws InterruptedException {
        MyThreadPool pool = new MyThreadPool();
        pool.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("111");
            }
        });
    }
}


相关文章
|
2月前
|
人工智能 缓存 安全
阿里云发布《AI 原生应用架构白皮书》
阿里云联合阿里巴巴爱橙科技,共同发布《AI 原生应用架构白皮书》,围绕 AI 原生应用的 DevOps 全生命周期,从架构设计、技术选型、工程实践到运维优化,对概念和重难点进行系统的拆解,并尝试提供一些解题思路。白皮书覆盖 AI 原生应用的 11 大关键要素,获得 15 位业界专家联名推荐,来自 40 多位一线工程师实践心的,全书合计超 20w 字,分为 11 章。
1814 16
|
10月前
|
消息中间件 Java 数据库
自研Java框架 Sunrays-Framework使用教程「博客之星」
### Sunrays-Framework:助力高效开发的Java微服务框架 **Sunrays-Framework** 是一款基于 Spring Boot 构建的高效微服务开发框架,深度融合了 Spring Cloud 生态中的核心技术组件。它旨在简化数据访问、缓存管理、消息队列、文件存储等常见开发任务,帮助开发者快速构建高质量的企业级应用。 #### 核心功能 - **MyBatis-Plus**:简化数据访问层开发,提供强大的 CRUD 操作和分页功能。 - **Redis**:实现高性能缓存和分布式锁,提升系统响应速度。 - **RabbitMQ**:可靠的消息队列支持,适用于异步
自研Java框架 Sunrays-Framework使用教程「博客之星」
|
缓存 JavaScript
Vue加载网络组件(远程组件)
【10月更文挑战第23天】在 Vue 中实现加载网络组件(远程组件)可以通过多种方式来完成。
|
SpringCloudAlibaba Java 关系型数据库
1.SpringCloud微服务搭建
1.SpringCloud微服务搭建
227 1
|
数据采集 机器学习/深度学习 算法
聚类算法
【6月更文挑战第6天】聚类算法是无监督学习方法,用于将数据集划分成相似样本的类别。常见的聚类算法有K均值、层次聚类和DBSCAN等。在分析时,涉及数据预处理、选择算法、确定聚类数目、执行聚类及评估结果。层次聚类分为自底向上和自顶向下两种,而K-Means是基于质心的聚类算法。评估指标如轮廓系数可衡量聚类效果。聚类过程包括初始化中心、计算样本与中心距离、分配类别和更新中心,直到收敛。
595 2
|
自然语言处理 安全 区块链
Chatchat:为语言链而生的新时代
Chatchat:为语言链而生的新时代
601 9
|
Java Maven
IDEA中查看源码点击Download Sources时出现Cannot download sources的问题复现及解决
IDEA中查看源码点击Download Sources时出现Cannot download sources的问题复现及解决
2139 0
|
前端开发 网络协议 Java
Netty | 工作流程图分析 & 核心组件说明 & 代码案例实践
Netty | 工作流程图分析 & 核心组件说明 & 代码案例实践
1049 1
|
Windows
Mac移动硬盘直接拔掉后,再插上无法显示的解决办法
Mac移动硬盘直接拔掉后,再插上无法显示的解决办法
|
人工智能 Java 容器
Spring中@Conditional注解详解
Spring中@Conditional注解详解