首页 > 其他分享 >手写线程池

手写线程池

时间:2022-10-09 10:07:54浏览次数:51  
标签:task 创建 线程 手写 public pool blockingQueue


 我们先不去看线程池原理,然后自己一步一步的分析,看看线程池都需要做哪些工作。

 然后再一步一步的实现它,然后再去对比比人写好的线程池,然后看看差距在哪里。

 

# # 先分析为什么要用线程池

  线程是任务调度的最小单位,其实可以这样理解,线程就是搬运的货车,将需要执行的字节码搬运给CPU去处理。

  如果不使用线程池的话,有可能无限的去创建线程,系统的资源是有限的,一个服务器,如果一直创建线程,就能崩溃掉。阿里开发规范里边明确禁止在程序中显示的创建线程。

  另外,即使系统资源够用,根据线程的生命周期,其实你创建的线程,在执行完以后似乎会销毁的。如果不用线程池,那就是帮我们搬运执行字节码的货车,只用用一次,用完一次就销毁,然后第二次用再创建一个,下次用还创建一个。线程的创建和销毁都是要消耗资源的,特备是大量的线程的创建更是。

  所以我们用池的技术,老统一管理我们的资源,让线程统一维护在一个池子里边,从而做到更加安全的使用。

 

# # 用一个海底捞的例子,来说说线程池的工作原理

  我们都知道,海底捞一般都是比较爆满的。但是海底捞的位子是有限的,如果你去的晚的话,可能就吃不上了。但是如果女朋友一定就要吃海底捞,别的不吃的话。就只能等等了。海底捞一般都会在门口放上一些椅子或者长凳,来吃的人,如果里边已经满了,就先在外边等一会儿,等里边的人吃完了,出来了,再进去。

  而换成线程,那么需要搬运到CPU执行的任务,就是要吃火锅的人。

 

# # 一个简单的线程池都需要哪些呢

  我们要一个长凳,来共消费者等待。这里我们只能使用阻塞队列。

  我们需要提前创建一定数量的线程,创建好,这些线程就一直不休息了。就像生产者消费者模式一样,这些线程都作为消费者,是我前边讲到的货车,等待拉货。这些货车则组成车队,放在一个地方统一管理。

 

# #  动手实践

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;

/**
* @author angus
* @create 2020-03-19 8:30
*/
public class MyThreadPool {
//1.存放想要被执行的任务
private BlockingQueue<Runnable> blockingQueue;

//2.存放固定数量的线程
private List<Thread> workers;

//线程池工作状态
private volatile boolean isWorking = true;

//3.创建线程
public static class Worker extends Thread{
private MyThreadPool pool;

public Worker(MyThreadPool pool){
this.pool = pool;
}
@Override
public void run(){
while (this.pool.isWorking || this.pool.blockingQueue.size() > 0){
Runnable task = null;
try {
if(this.pool.isWorking){
task = this.pool.blockingQueue.take();
}else {
task = this.pool.blockingQueue.poll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
if(task != null){
task.run();
System.out.println("task:" + Thread.currentThread().getName() + "执行完毕");
}
}
}
}
public MyThreadPool(int taskSize, int poolSize){
if(taskSize <= 0 || poolSize <= 0){
throw new IllegalArgumentException("非法参数,taskSize 和 poolSize 必须大于0");
}
this.blockingQueue = new LinkedBlockingDeque<>(taskSize);
this.workers = new ArrayList<>();
for (int i = 0; i < poolSize; i++) {
Worker worker = new Worker(this);
worker.start();
workers.add(worker);
}
}
// 放入执行任务
public boolean submit(Runnable task){
if(isWorking){
return this.blockingQueue.offer(task);
}else {
return false;
}
}

// 关闭线程池
public void shutDown(){
this.isWorking = false;
for (Thread worker:workers){
if(worker.getState().equals(Thread.State.BLOCKED)){
worker.interrupt();
}
}
}
}

 

  测试:

/**
* @author angus
* @create 2020-03-19 9:27
*/
public class MyThreadPoolDemo {
public static void main(String[] args) {
MyThreadPool pool = new MyThreadPool(3,3);
for (int i = 0; i < 3; i++) {
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println("##");
}
});
}
pool.shutDown();
}
}

 

标签:task,创建,线程,手写,public,pool,blockingQueue
From: https://blog.51cto.com/u_15812686/5739735

相关文章

  • Java 多线程(一)线程简介
    多任务类似于这些例子,现实生活中太多太多了。看起来是多个任务在做,其实本质上我们的大脑再同一时间依旧只做一件事。 多线程  原来是一条路,慢慢的因为车多起来......
  • 线程池
    池化技术线程属于稀缺资源,由于创建线程和销毁线程十分消耗内存和资源,因此实现线程的复用十分重要将创建的线程存入线程池管理,实现线程的复用,提高了cpu利用率池化技术,比......
  • Python 守护线程
    如果你设置一个线程为守护线程,,就表示你在说这个线程是不重要的,在进程退出的时候,不用等待这个线程退出。如果你的主线程在退出的时候,不用等待那些子线程完成,那就设置这些线......
  • 阻塞队列、线程池、原子性及并发工具类
    目录​​一、阻塞队列​​​​二、线程池​​​​静态方法创建线程池:​​​​使用ThreadPoolexecutor类创建线程池:​​​​三、原子性​​​​四、并发工具类​​​​HashTa......
  • 同步代码块、同步方法解决数据安全问题、线程安全的类及Lock锁
    目录​​一、同步代码块解决数据安全问题​​​​二、同步方法解决数据安全问题​​​​三、线程安全的类​​​​四、Lock锁​​一、同步代码块解决数据安全问题安全问题出......
  • ThreadLocal本地局部线程demo
    ThreadLocal本地局部线程demoimportorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importjava.util.HashMap;importjava.util.Map;/***本工具只能保存一......
  • 35+,如果面试让我手写红黑树!
    作者:小傅哥博客:https://bugstack.cn沉淀、分享、成长,让自己和他人都能有所收获!......
  • Java中如何实现两个线程交替运行呢?
    今天笔者收到老师的一个题目,让我准备两个流程,依次实现输出以下信息 如:  线程A打印字母a,线程B打印数字1线程A打印字母b,线程B打印数字2线程A打印字母......
  • 手写一个AQS实现
    1.背景2.代码-基础准备2.1.Node节点对象创建在MyReentrantLock对象内建立一个Node节点对象,后面作为双向链表的节点;publicclassMyReentrantLock{/***......
  • Python多线程
    一、概念线程是CPU分配资源的基本单位,当程序开始运行,这个程序就变成了一个进程;当有多线程编程时,一个进程包含多个线程(含主线程),使用线程可以实现程序大的开发任务。多线......