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

目录

线程池

一、线程池是什么

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

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

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

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

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

相关推荐
Java水解6 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
CYRUS_STUDIO6 小时前
用 Frida 控制 Android 线程:kill 命令、挂起与恢复全解析
android·linux·逆向
CYRUS_STUDIO6 小时前
Frida 实战:Android JNI 数组 (jobjectArray) 操作全流程解析
android·逆向
洛小豆8 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学8 小时前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端
ytadpole9 小时前
Spring Cloud Gateway:一次不规范 URL 引发的路由转发404问题排查
java·后端
华仔啊9 小时前
基于 RuoYi-Vue 轻松实现单用户登录功能,亲测有效
java·vue.js·后端
程序员鱼皮9 小时前
刚刚 Java 25 炸裂发布!让 Java 再次伟大
java·javascript·计算机·程序员·编程·开发·代码
浮游本尊10 小时前
Java学习第21天 - 微服务架构设计
java