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

目录

线程池

一、线程池是什么

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

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

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

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

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

相关推荐
2301_780789667 小时前
跨平台适配!SDK 游戏盾兼容全终端游戏场景
java·网络·ddos
第九序言T7 小时前
Python 数据处理进阶(十八)批量处理同结构文件:一个文件夹一次跑完
开发语言·python·自动化·pandas·数据处理
学长毕设8 小时前
基于springboot的食品仓库管理系统
java·spring boot·后端
步行cgn9 小时前
FormHttpMessageConverter 详解:Spring MVC 中表单数据的读写转换器
java·spring·mvc
龙亘川9 小时前
构建城市公共安全数字底座:亘川智城智慧安防系统全维度解读
java·大数据·开发语言·人工智能·信息可视化
金銀銅鐵9 小时前
[Java] 用 CLI 展示 EnumMap 增删键值对时的内部变化
java·源码·ai编程
程序喵大人9 小时前
【C++入门】内存模型与资源管理 - 09 shared_ptr 和 weak_ptr 解决共享,也带来代价
开发语言·c++·资源管理·智能指针·内存模型
秋天的怀念_David9 小时前
第二十二夜 · 数字迷雾
java·程序人生·算法
Raas1009 小时前
AI网关部署方案?从部署到上线全流程
java·开发语言·人工智能·gateway·ai网关·企业级ai网关·企业级ai产品
niucloud-admin10 小时前
NIUCLOUD PHP SAAS上门家政使用文档:城市管理
java·前端·php