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

目录

线程池

一、线程池是什么

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

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

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

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

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

相关推荐
秋の花2 分钟前
【JAVA基础】Java集合基础
java·开发语言·windows
小松学前端4 分钟前
第六章 7.0 LinkList
java·开发语言·网络
Wx-bishekaifayuan11 分钟前
django电商易购系统-计算机设计毕业源码61059
java·spring boot·spring·spring cloud·django·sqlite·guava
可峰科技13 分钟前
斗破QT编程入门系列之二:认识Qt:编写一个HelloWorld程序(四星斗师)
开发语言·qt
customer0816 分钟前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
全栈开发圈18 分钟前
新书速览|Java网络爬虫精解与实践
java·开发语言·爬虫
WaaTong20 分钟前
《重学Java设计模式》之 单例模式
java·单例模式·设计模式
面试鸭22 分钟前
离谱!买个人信息买到网安公司头上???
java·开发语言·职场和发展
小白学大数据23 分钟前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫