学生视角手把手带你写Java 线程池初版

 更新时间:2022年03月21日 11:16:08   作者:摸鱼打酱油  
作者是一个来自河源的大三在校生,以下笔记都是作者自学之路的一些浅薄经验,如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门

Java手写线程池(第一代)

经常使用线程池,故今天突发奇想,手写一个线程池,会有很多不足,请多多宽容。因为这也是第一代的版本,后续会更完善。

手写线程池-定义参数

	private final AtomicInteger taskcount=new AtomicInteger(0);
    private final AtomicInteger threadNumber=new AtomicInteger(0);
    private volatile int corePoolSize; 
    private final Set<MyThreadPoolExecutor.MyWorker> workers; 
    private final BlockingQueue<Runnable> waitingQueue; 
    private final String THREADPOOL_NAME="MyThread-Pool-";
    private volatile boolean isRunning=true; 
    private volatile boolean STOPNOW=false; 
    private final ThreadFactory threadFactory; 
  • taskcount:执行任务次数
  • threadNumber:线程编号,从0开始依次递增。
  • corePoolSize:核心线程数
  • workers:工作线程
  • waitingQueue:等待队列
  • THREADPOOL_NAME:线程名称
  • isRunning:是否运行
  • STOPNOW:是否立刻停止
  • threadFactory:线程工厂

手写线程池-构造器

    public MyThreadPoolExecutor(int corePoolSize, BlockingQueue<Runnable> waitingQueue,ThreadFactory threadFactory) {
        this.corePoolSize=corePoolSize;
        this.workers=new HashSet<>(corePoolSize);
        this.waitingQueue=waitingQueue;
        this.threadFactory=threadFactory;
        //线程预热
        for (int i = 0; i < corePoolSize; i++) {
            new MyWorker();
        }
    }

该构造器作用:

1:对参数进行赋值。

2:线程预热。根据corePoolSize的大小来调用MyWorker的构造器。我们可以看看MyWorker构造器做了什么。

	final Thread thread; //为每个MyWorker

        MyWorker(){
            Thread td = threadFactory.newThread(this);
            td.setName(THREADPOOL_NAME+threadNumber.getAndIncrement());
            this.thread=td;
            this.thread.start();
            workers.add(this);
        }
  • MyWorker构造器通过线程工厂对当前对象生成Thread;
  • 并设置线程名为:MyThread-Pool-自增线程编号;
  • 然后调用线程的start方法启动线程;
  • 最后存放在workers这个Set集合中,这样就可以实现线程复用了。

手写线程池-默认构造器

	public MyThreadPoolExecutor(){
        this(5,new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory());
    }
  • 默认构造器的赋初始值:
  • corePoolSize:5
  • waitingQueue:new ArrayBlockingQueue<>(10),长度为10的有限阻塞队列
  • threadFactory:Executors.defaultThreadFactory()

手写线程池-execute方法

	public boolean execute(Runnable runnable)
    {
        return waitingQueue.offer(runnable);
    }
  • 本质上其实就是把Runnable(任务)放到waitingQueue中。

手写线程池-处理任务

	   @Override
        public void run() {
            //循环接收任务
                while (true)
                {
                    if((!isRunning&&waitingQueue.size()==0)||STOPNOW)
                    {
                        break;
                    }else {
                        Runnable runnable = waitingQueue.poll();
                        if(runnable!=null){
                            runnable.run();
                            System.out.println("task==>"+taskcount.incrementAndGet());
                        }
                    }
                }
        }

本质上就是一个死循环接收任务,退出条件如下:

  • 优雅的退出。当isRunning为false并且waitingQueue的队列大小为0(也就是无任务了)
  • 暴力退出。当STOPNOW为true,则说明调用了shutdownNow方法
  • else语句块会不断取任务,当任务!=null时则调用run方法处理任务

手写线程池-优雅关闭线程池

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

手写线程池-暴力关闭线程池

	public void shutdownNow()
    {
        this.STOPNOW=true;
    }

手写线程池-源代码

  • 手写线程池类的源代码
package com.springframework.concurrent;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程池类
 * @author 游政杰
 */
public class MyThreadPoolExecutor {

    private final AtomicInteger taskcount=new AtomicInteger(0);//执行任务次数
    private final AtomicInteger threadNumber=new AtomicInteger(0); //线程编号
    private volatile int corePoolSize; //核心线程数
    private final Set<MyThreadPoolExecutor.MyWorker> workers; //工作线程
    private final BlockingQueue<Runnable> waitingQueue; //等待队列
    private final String THREADPOOL_NAME="MyThread-Pool-";//线程名称
    private volatile boolean isRunning=true; //是否运行
    private volatile boolean STOPNOW=false; //是否立刻停止
    private final ThreadFactory threadFactory; //线程工厂

    public MyThreadPoolExecutor(){
        this(5,new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory());
    }

    public MyThreadPoolExecutor(int corePoolSize, BlockingQueue<Runnable> waitingQueue,ThreadFactory threadFactory) {
        this.corePoolSize=corePoolSize;
        this.workers=new HashSet<>(corePoolSize);
        this.waitingQueue=waitingQueue;
        this.threadFactory=threadFactory;
        //线程预热
        for (int i = 0; i < corePoolSize; i++) {
            new MyWorker();
        }
    }

    /**
     * MyWorker就是我们每一个线程对象
     */
    private final class MyWorker implements Runnable{

        final Thread thread; //为每个MyWorker

        MyWorker(){
            Thread td = threadFactory.newThread(this);
            td.setName(THREADPOOL_NAME+threadNumber.getAndIncrement());
            this.thread=td;
            this.thread.start();
            workers.add(this);
        }

        @Override
        public void run() {
            //循环接收任务
                while (true)
                {
                    //循环退出条件:
                    //1:当isRunning为false并且waitingQueue的队列大小为0(也就是无任务了),会优雅的退出。
                    //2:当STOPNOW为true,则说明调用了shutdownNow方法进行暴力退出。
                    if((!isRunning&&waitingQueue.size()==0)||STOPNOW)
                    {
                        break;
                    }else {
                        //不断取任务,当任务!=null时则调用run方法处理任务
                        Runnable runnable = waitingQueue.poll();
                        if(runnable!=null){
                            runnable.run();
                            System.out.println("task==>"+taskcount.incrementAndGet());
                        }
                    }
                }
        }
    }

    public boolean execute(Runnable runnable)
    {
        return waitingQueue.offer(runnable);
    }
    //优雅的关闭
    public void shutdown()
    {
        this.isRunning=false;
    }
    //暴力关闭
    public void shutdownNow()
    {
        this.STOPNOW=true;
    }
}
  • 测试使用手写线程池代码
package com.springframework.test;

import com.springframework.concurrent.MyThreadPoolExecutor;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;

public class ThreadPoolTest {

  public static void main(String[] args) {

    
      MyThreadPoolExecutor myThreadPoolExecutor = new MyThreadPoolExecutor
              (5,new ArrayBlockingQueue<>(6), Executors.defaultThreadFactory());

      for(int i=0;i<10;i++){

          int finalI = i;
          myThreadPoolExecutor.execute(()->{
              System.out.println(Thread.currentThread().getName()+">>>>"+ finalI);
          });

      }

      myThreadPoolExecutor.shutdown();

//      myThreadPoolExecutor.shutdownNow();



  }
}

问题

为什么自定义线程池的execute执行的任务有时会变少?

那是因为waitingQueue满了放不下任务了,导致任务被丢弃,相当于DiscardPolicy拒绝策略

解决办法有:

1:设置最大线程数,自动对线程池扩容。

2:调大waitingQueue的容量capacity

最后:因为这是我手写的线程池的初代版本,基本实现线程池的复用功能,然而还有很多未完善,将来会多出几篇完善后的文章,对目前手写的线程池进行升级。

后续还会继续出关于作者手写Spring框架,手写Tomcat等等框架的博文!!!!!

到此这篇关于学生视角手把手带你写Java 线程池的文章就介绍到这了,更多相关Java 线程池内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring Boot 项目搭建教程及注解

    Spring Boot 项目搭建教程及注解

    下面小编就为大家带来一篇Spring Boot 项目搭建教程及注解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • Spring AOP快速入门及开发步骤

    Spring AOP快速入门及开发步骤

    Spring AOP(面向切面编程)核心概念包括切面(Aspect)、连接点(JoinPoint)、切点(Pointcut)、通知(Advice)等,通过在不改变原代码的情况下,对方法进行增强,实现了代码的解耦和功能扩展,本文带来大家掌握Spring 中 AOP 的开发步骤,感兴趣的朋友一起看看吧
    2024-10-10
  • java使用CountDownLatch等待多线程全部执行完成

    java使用CountDownLatch等待多线程全部执行完成

    这篇文章主要为大家详细介绍了使用CountDownLatch等待多线程全部执行完成,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-10-10
  • 深入浅析hbase的优点

    深入浅析hbase的优点

    本文讲述了HBase的特征和它的优点,并简要回顾了行键设计的重点之处,它还向你展示了如何在本地配置HBase环境,使用命令创建表、插入数据、检索指定行以及最后如何进行scan操作,感兴趣的朋友一起看看吧
    2017-09-09
  • Java数据库操作库DButils类的使用方法与实例详解

    Java数据库操作库DButils类的使用方法与实例详解

    这篇文章主要介绍了JDBC数据库操作库DButils类的使用方法详解,需要的朋友可以参考下
    2020-02-02
  • 详解Eclipse Validating缓慢的优化

    详解Eclipse Validating缓慢的优化

    这篇文章主要介绍了详解Eclipse Validating缓慢的优化,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • ZooKeeper入门教程一简介与核心概念

    ZooKeeper入门教程一简介与核心概念

    本文是ZooKeeper入门系列教程,涵盖ZooKeeper核心内容,通过实例和大量图表,结合实战,帮助学习者理解和运用,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2022-01-01
  • Java实现threadLocal线程池获取

    Java实现threadLocal线程池获取

    本文主要介绍了Java实现threadLocal线程池获取,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • java加载属性配置properties文件的方法

    java加载属性配置properties文件的方法

    这篇文章主要介绍了java加载属性配置properties文件的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • 详解Java中的final关键字

    详解Java中的final关键字

    子类可以在父类的基础上改写父类内容,为了避免这种随意改写的情况,Java提供了final 关键字,用于修饰不可改变内容。本文就来详细说说final关键字的使用,需要的可以参考一下
    2022-10-10

最新评论