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

目录

线程池

一、线程池是什么

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

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

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

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

二、底层线程池 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类的封装.

相关推荐
Dwzun6 分钟前
基于SpringBoot+Vue的二手书籍交易平台系统【附源码+文档+部署视频+讲解)
java·vue.js·spring boot·后端·spring·计算机毕业设计
期待のcode10 分钟前
Wrapper体系中的condition参数
java·spring boot·后端·mybatis
程序员陆业聪13 分钟前
Android插件化原理与方案详解
android
肥大毛20 分钟前
C++入门学习---结构体
开发语言·c++·学习
小明记账簿21 分钟前
JavaScript浮点数精度问题及解决方案
开发语言·javascript·ecmascript
雨中飘荡的记忆34 分钟前
Spring状态机深度解析
java·后端·spring
BBB努力学习程序设计36 分钟前
Java记录类(Records)与数据建模革命:从POJO到不可变数据的范式转变
java
南棱笑笑生36 分钟前
20251213给飞凌OK3588-C开发板适配Rockchip原厂的Buildroot【linux-6.1】系统时适配type-C0
linux·c语言·开发语言·rockchip
月屯43 分钟前
Pandoc 之--pdf-engine
java·开发语言·pdf