手写一个简单的线程池

添砖java的啾
• 阅读 1316

  有些人可能对线程池比较陌生,并且更不熟悉线程池的工作原理。所以他们在使用线程的时候,多数情况下都是new Thread来实现多线程。但是,往往良好的多线程设计大多都是使用线程池来实现的。

为什么要使用线程池

  1. 可以降低线程创建和销毁的资源消耗。
  2. 可以提高响应速度。线程的创建时间为T1,执行时间T2,销毁时间T3,通过使用线程池,可以免去T1和T3的时间
  3. 可以提高线程的可管理性

下图所示为线程池的实现原理:
   调用方不断向线程池中提交任务,线程池中的线程不断地从队列中取任务,这是一个典型的生产者-消费者模型。

手写一个简单的线程池

实战:手写简易线程池

  现在来带大家手写一个简单的线程池,让大家更加理解线程池的工作原理

/**
 * 自定义线程池
 */

public class ThreadPool {

    /** 默认线程池中的线程的数量 */
    private static final int WORK_NUM = 5;

    /** 默认处理任务的数量 */
    private static final int TASK_NUM = 100;

    /** 存放任务 */
    private final BlockingQueue<Runnable> taskQueue;

    private final Set<WorkThread> workThreads;//保存线程的集合

    private int workNumber;//线程数量

    private int taskNumber;//任务数量

    public ThreadPool(){
        this(WORK_NUM , TASK_NUM);
    }

    public ThreadPool(int workNumber , int taskNumber) {
        if (taskNumber<=0){
            taskNumber = TASK_NUM;
        }
        if (workNumber<=0){
            workNumber = WORK_NUM;
        }
        this.taskQueue = new ArrayBlockingQueue<Runnable>(taskNumber);
        this.workNumber = workNumber;
        this.taskNumber = taskNumber;

        workThreads = new HashSet<>();

        //工作线程准备好了
        //启动一定数量的线程数,从队列中获取任务处理
        for (int i=0;i<workNumber;i++) {
            WorkThread workThread = new WorkThread("thead_"+i);
            workThread.start();
            workThreads.add(workThread);
        }
    }

    /**
     * 线程池执行任务的方法,其实就是往BlockingQueue中添加元素
     * @param task
     */

    public void execute(Runnable task) {
        try {
            taskQueue.put(task);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


    /**
     * 销毁线程池
     */

    public void destroy(){
        System.out.println("ready close pool...");
        for (WorkThread workThread : workThreads) {
            workThread.stopWorker();
            workThread = null;//help gc
        }
        workThreads.clear();
    }

    /** 内部类,工作线程的实现 */
    private class WorkThread extends Thread{
        public WorkThread(String name){
            super();
            setName(name);
        }
        @Override
        public void run() {
            while (!interrupted()) {
                try {
                    Runnable runnable = taskQueue.take();//获取任务
                    if (runnable !=null) {
                        System.out.println(getName()+" ready execute:"+runnable.toString());
                        runnable.run();//执行任务
                    }
                    runnable = null;//help gc
                } catch (Exception e) {
                    interrupt();
                    e.printStackTrace();
                }
            }
        }

        public void stopWorker(){
            interrupt();
        }
    }
}

  上面代码定义了默认的线程数量和默认处理任务数量,同时用户也可以自定义线程数量和处理任务数量。

  我们使用BlockingQueue阻塞队列(之后会具体介绍)来存放任务。用set来存放工作线程;
   构造方法中new对象的时候,循环启动线程,并把线程放入set中。
   通过实现实现Thread来创建WorkThread类; 因为有一个stop方法,所以这里需要while判断,之后从taskQueue队列中获取任务。获取不到就阻塞,获取到的话runnable.run();就执行任务,之后把任务变成null; 销毁线程只需要遍历set,把每个线程停止,并且变为null; 执行线程任务execute

我们来测试一下:

public class TestMySelfThreadPool {

    private static final int TASK_NUM = 50;//任务的个数

    public static void main(String[] args) {
        ThreadPool myPool = new ThreadPool(3,50);
        for (int i=0;i<TASK_NUM;i++) {
            myPool.execute(new MyTask("task_"+i));
        }

    }

    static class MyTask implements Runnable{

        private String name;
        public MyTask(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }


        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("task :"+name+" end...");

        }

        @Override
        public String toString() {
            // TODO Auto-generated method stub
            return "name = "+name;
        }
    }
}

结果ok,没什么问题。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
海军 海军
3年前
系统刷JavaScripit 构建前端体系(语法篇)
前言<sectionid"nice"datatool"mdnice编辑器"datawebsite"https://www.mdnice.com"style"fontsize:16px;padding:010px;wordspacing:0px;wordbreak:breakword;wordwrap:breakword;text
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
海军 海军
3年前
2021前端技术面试必备Vue:(三)Router篇
<sectionid"nice"datatool"mdnice编辑器"datawebsite"https://www.mdnice.com"style"padding:010px;wordspacing:0px;wordwrap:breakword;textalign:left;fontfamily:Opti
添砖java的啾 添砖java的啾
3年前
如何编写高质量的代码
<sectionid"nice"datatool"mdnice编辑器"datawebsite"https://www.mdnice.com"style"lineheight:1.6;wordbreak:breakword;wordwrap:breakword;textalign:left;fontfamily:OptimaRegul
添砖java的啾 添砖java的啾
3年前
如何写出"简单"代码?
<sectionid"nice"datatool"mdnice编辑器"datawebsite"https://www.mdnice.com"style"lineheight:1.6;wordbreak:breakword;wordwrap:breakword;textalign:left;fontfamily:OptimaRegul
海军 海军
3年前
[前端必知 ]HTTP or TCP/IP 基础
<sectionid"nice"datatool"mdnice编辑器"datawebsite"https://www.mdnice.com"style"fontsize:16px;padding:010px;wordspacing:0px;wordbreak:breakword;wordwrap:break
不才 不才
3年前
mysql 基础学习笔记
<sectionid"nice"datatool"mdnice编辑器"datawebsite"https://www.mdnice.com"style"fontsize:16px;padding:010px;wordspacing:0px;wordbreak:breakword;wordwrap:break
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
添砖java的啾
添砖java的啾
Lv1
一只添砖java的啾
文章
4
粉丝
1
获赞
3