【操作系统】线程池的底层逻辑解析及实现

目录

线程池

一、线程池是什么

在我们频繁的创建线程时或销毁线程时,都会进行系统调度从而占用系统资源,虽然创建线程/销毁线程的开销不是很大,但架不住量多,进而我们该如何避免这种情况呢?

引入线程池就能完美的解决上面的问题了.

那么什么是线程池呢?简单来说就是在创建线程之前先估计要用到的线程数量多少,直接创建一个大池子,把这些线程放在池子里,当用到的时候直接从池子中取出使用,不用了在放回线程池就行,当我们的任务结束后对线程池进行销毁即可,从而免去中中间不断创建的麻烦和浪费的资源.

线程池最⼤的好处就是减少每次启动、销毁线程的损耗。

二、底层线程池 ThreadPoolExecutor

ThreadPoolExecutor提供了更多的可选参数,可以进⼀步细化线程池行为的设定.

  • corePoolSize:正式员工的数量.(正式员工,⼀旦录用,永不辞退)
  1. maximumPoolSize:正式员工+临时工的数⽬.(临时工:⼀段时间不⼲活,就被辞退).

  2. keepAliveTime:临时工允许的空闲时间.

  3. unit:keepaliveTime的时间单位,是秒,分钟,还是其他值.

  4. workQueue:传递任务的阻塞队列

  5. threadFactory:创建线程的工⼚,参与具体的创建线程工作.通过不同线程工⼚创建出的线程相当于对⼀些属性进行了不同的初始化设置.

  6. RejectedExecutionHandler:拒绝策略,如果任务量超出公司的负荷了接下来怎么处理.

    1. AbortPolicy():超过负荷,直接抛出异常.
    2. CallerRunsPolicy():调用者负责处理多出来的任务.
    3. DiscardOldestPolicy():丢弃队列中最⽼的任务.
    4. DiscardPolicy():丢弃新来的任务.

三、实现线程池

  1. 核⼼操作为submit,将任务加⼊线程池中

  2. 使用Worker类描述⼀个工作线程.使用Runnable描述⼀个任务.

  3. 使用⼀个BlockingQueue组织所有的任务

  4. 每个worker线程要做的事情:不停的从BlockingQueue中取任务并执行. •

  5. 指定⼀下线程池中的最⼤线程数maxWorkerCount;当当前线程数超过这个最⼤值时,就不再新增 线程了.

实现代码如下:

java 复制代码
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

class MyThreadPool {
    private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
    // 通过这个方法, 来把任务添加到线程池中.
    public void submit(Runnable runnable) throws InterruptedException {
        queue.put(runnable);
    }
    // n 表⽰线程池⾥有⼏个线程.
// 创建了⼀个固定数量的线程池.
    public MyThreadPool(int n) {
        for (int i = 0; i < n; i++) {
            Thread t = new Thread(() -> {
                while (true) {
                    try {
// 取出任务, 并执行~~
                        Runnable runnable = queue.take();
                        runnable.run();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.start();
        }
    }
}

执行代码如下:

java 复制代码
// 线程池
public class Demo {
    public static void main(String[] args) throws InterruptedException {
        MyThreadPool pool = new MyThreadPool(4);
        for (int i = 0; i < 1000; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
// 要执行的工作
                    System.out.println(Thread.currentThread().getName() + " hell
                }
            });
        }
    }
}

四、标准库中的线程池Executors

  • 使用Executors.newFixedThreadPool(10)能创建出固定包含10个线程的线程池.
  • 返回值类型为ExecutorService
  • 通过ExecutorService.submit可以注册⼀个任务到线程池中.
java 复制代码
ExecutorService pool = Executors.newFixedThreadPool(10);
	pool.submit(new Runnable() {
		@Override
		public void run() {
			System.out.println("hello");
		}
	});

Executors创建线程池的⼏种方式:

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

  • newCachedThreadPool:创建线程数⽬动态增⻓的线程池.

  • newSingleThreadExecutor:创建只包含单个线程的线程池.

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

Executors本质上是ThreadPoolExecutor类的封装.

相关推荐
I_Am_Me_2 分钟前
【JavaEE进阶】 JavaScript
开发语言·javascript·ecmascript
重生之我是数学王子12 分钟前
QT基础 编码问题 定时器 事件 绘图事件 keyPressEvent QT5.12.3环境 C++实现
开发语言·c++·qt
xmh-sxh-131413 分钟前
jdk各个版本介绍
java
Ai 编码助手14 分钟前
使用php和Xunsearch提升音乐网站的歌曲搜索效果
开发语言·php
学习前端的小z18 分钟前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
神仙别闹26 分钟前
基于C#和Sql Server 2008实现的(WinForm)订单生成系统
开发语言·c#
XINGTECODE27 分钟前
海盗王集成网关和商城服务端功能golang版
开发语言·后端·golang
天天扭码32 分钟前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶33 分钟前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺37 分钟前
Spring Boot框架Starter组件整理
java·spring boot·后端