线程池原理:手写简单的线程池

线程池原理:手写简单线程池

一、线程池作用

  • 1.提高程序执行效率,并发执行提高响应速度;
  • 2.线程复用,减少频繁创建销毁线程对服务器的性能消耗
  • 3.有利于对线程进行管理

二、线程池基本的常见构成要素

  • 1.执行的线程数量,开启执行的线程;
  • 2.执行的任务集合
  • 3.构造方法
  • 4.executor方法(有返回值)或submit方法(无返回值)
  • 5.shutdown停止线程的方法

在这里插入图片描述
参考简图:

三、手写简单线程池样例,有利于加深对线程池工作原理的理解

package com.demo.spring.test.threadPool;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * @Description: 简单模拟手写线程池,方便理解线程池工作原理
 * @Author: 狗狗大蛇
 * @Date:
 
 */
public class MyThreadPoolExecutor {

    // 工作线程集合
    private List<TaskThread> threads;

    // 阻塞队列:executor(Runnable 实参)传进来的工作任务均先存放到该队列中,等待TaskThread去取出来执行;
    private BlockingQueue<Runnable> workQueue;

    // 控制线程池停止的标记
    private volatile Boolean shutDownFlag = true;

    /**
     * 线程池构造方法
     * @param threadNum : 初始创建保持运行状态线程的数量
     * @param works : 线程池处理的工作任务数量
     */
    public MyThreadPoolExecutor(int threadNum,int works){

        // 创建指定大小的队列容器,用于存放任务;
        this.workQueue = new LinkedBlockingQueue<>(works);

        // 创建threadNum运行状态的线程数量,并进入就绪状态
        this.threads = new ArrayList<>();
        for(int i = 0 ; i < threadNum; i++){
            TaskThread workThread = new TaskThread();
            Thread thread = new Thread(workThread);
            thread.start();
            this.threads.add(workThread);
        }


    }

    /**
     * 定义一个工作线程:也叫服务线程:指不断获取队列中的消息来进行处理的线程;
     * 1.在线程池中始终保持运行状态;
     * 2.不停的去工作任务队列中去取任务;
     */
    class TaskThread implements Runnable{
        @Override
        public void run() {
            // 1.如果要线程保持运行状态,需要写死循环
            while (shutDownFlag){
                // 2.队列中取任务执行,取完删掉对应任务;
                Runnable task = null;
                try {
                    // 此处不用poll,poll会不停的取,导致CPU使用率居高不下;用take没有任务以后会等待,CPU使用率消耗特别低;
                    task = workQueue.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(null != task){
                    task.run();
                }
            }
        }
    }

    /**
     * 线程池启动执行的方法
     * @param runnable 放入需要执行的业务任务线程;
     * @return
     */
    public void executor(Runnable runnable){
        // 将业务线程放到队列容器中,运行中的线程会不停的到队列中取任务;
        // offer(): 非阻塞式添加任务
        try {
            workQueue.put(runnable);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void shutdown(){
        this.shutDownFlag = false;
    }

    // 测试效果
    public static void main(String[] args) throws InterruptedException {
        MyThreadPoolExecutor myThreadPoolExecutor = new MyThreadPoolExecutor(4,8);
        SendEmailTask sendEmailTask = new SendEmailTask();
        boolean flag = false;
        for(int i = 0; i < 100; i++){
            myThreadPoolExecutor.executor(sendEmailTask);
            if( i == 99 ){
                flag = true;
            }
        }

		// 模拟等待10秒后又有新的任务调用线程
        Thread.sleep(10000);
        System.out.println("模拟等待10秒");
        myThreadPoolExecutor.executor(sendEmailTask);
        System.out.println("结束");

		// 模拟等待10秒没有任务,停止线程
        Thread.sleep(10000);
        if(flag){
            myThreadPoolExecutor.shutdown();
        }

    }


}

/**
 * @Description: 具体发送邮件的业务线程
 * @Author: yangshilei
 * @Date:
 */
class SendEmailTask implements Runnable{

    @Override
    public void run() {
        try {
            // 模拟实际业务处理占用的时间
            Thread.sleep(new Random().nextInt(2000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程:"+Thread.currentThread().getName() + ":" + "短信发送成功");
    }

}

四、执行结果
我们可以看到已经实现了线程的复用:
且始终只有0,1,2,3这4开启的线程;

线程:Thread-3:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-2:短信发送成功

线程:Thread-1:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-3:短信发送成功


线程:Thread-0:短信发送成功

线程:Thread-1:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-3:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-0:短信发送成功
线程:Thread-1:短信发送成功
线程:Thread-2:短信发送成功
线程:Thread-3:短信发送成功
模拟等待10秒
结束
线程:Thread-0:短信发送成功

五、测试过程中发现CPU占用过高的问题以及处理方法
在使用poll()方法获取任务,导致CPU占用率很高,如下截图:
在这里插入图片描述
处理办法,将poll()换成take()进行获取任务,没有任务时候等待任务;测试代码中最后部分就是测试,等待后有新任务是否会生效的测试,如下代码和截图:

// 模拟等待10秒后又有新的任务调用线程
        Thread.sleep(10000);
        System.out.println("模拟等待10秒");
        myThreadPoolExecutor.executor(sendEmailTask);
        System.out.println("结束");

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值