开发极简版Java线程池需要10分钟,让朋友们更好地理解线程池的核心原理。
本文从华为云社区分享“放大招式”,冰河带您手持Java线程池10分钟,yyds,赶快收藏吧,作者:冰 河。Java线程池的核心原理
看过Java线程池源代码的朋友都知道,Java线程池的核心类别是ThreadPolexecutor,而ThreadPolexecutor类别的核心结构方法是具有7个参数的结构方法,如下所示。 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue
各参数的含义如下所示。 corePoolSize:常驻核心线程数在线程池中。 maximumPoolSize:线程池可容纳同时执行的最大线程数,大于或等于1。 keepAliveTime:多余的空闲线程存活时间,当空间时间达到keepalivetime值时,多余的线程会被销毁,直到只剩下corepolsize一个线程。 unit:keepalivetime单位。 workQueue:提交但尚未执行的任务队列。 threadFactory:线程工厂表示生成线程池中的工作线程,用户可以创建新的线程,通常可以默认使用。 handler:拒绝策略意味着当线程队列满,工作线程大于等于线程池的最大显示数时(maxnumPoolSize)如何拒绝要求执行的runnable策略?
而Java的线程池是通过生产者-消费者模式实现的,线程池的用户是生产者,而线程池本身就是消费者。
Java线程池的核心工作流程如下图所示。
手拉Java线程池
我们手动实现的线程池比Java自己的线程池简单得多。我们删除了各种复杂的处理方法,只保留了核心原理:线程池用户将任务添加到任务队列中,而线程池本身从任务队列中消耗任务并执行任务。
只要我们理解了这个核心原理,下一个代码就会简单得多。在实现这个简单的线程池时,我们可以拆卸整个实现过程。拆卸后的实现过程是:定义核心字段,创建内部WorkThread、创建ThreadPool类的结构方法和执行任务的方法。
定义核心字段
首先,我们创建了一个名为ThreadPol的Java类别,并在此类别中定义了以下核心字段。 DEFAULT_WORKQUEUE_SIZE:静态常量表示默认阻塞队列的大小。 workQueue:模拟实际的线程池使用阻塞队列来实现生产者-消费者模式。 workThreads:List集合保存线程池内的工作线程用于模拟实际线程池。
核心代码如下所示。 ///默认阻塞队列大小的privatete static final int DEFAULT_WORKQUEUE_SIZE = 5;///模拟实际线程池使用阻塞队列来实现生产者-消费者模式privatete BlockingQueue
在ThreadPol类中创建内部WorkThread,模拟线程池中的工作线程。主要功能是消耗workQue中的任务并执行任务。由于工作线程需要从workQue中不断获取任务,因此在这里使用while(true)循环不断尝试消费队列中的任务。
核心代码如下所示。 ///内部WorkThread,模拟线程池中的工作线程///主要作用是消耗workQueue中的任务,执行///因为工作线程需要不断从workQueue中获取任务,使用while(true)循环不断尝试消费队列中的任务class WorkThread extends Thread{ @Override public void run() { ////不断循环获取队列中的任务 while (true){ //当没有任务时,会阻塞 try { Runnable workTask = workQueue.take(); workTask.run(); } catch (InterruptedException e) { e.printStackTrace(); } } }} 创建ThreadPol类的构造方法
在这里,我们为ThreadPool创建了两种结构方法,一种是导入线程池的容量大小,另一种是导入线程池的容量大小。
核心代码如下所示。 ////将线程池的大小和阻塞队列publicc传入ThreadPol的结构方法 ThreadPool(int poolSize, BlockingQueue
execute()在ThreadPol类中创建执行任务的方法,execute()方法的实现相对简单,即将方法接收到的Runnable任务添加到workQueue队列中。
核心代码如下所示。 //通过线程池执行任务public void execute(Runnable task){ try { workQueue.put(task); } catch (InterruptedException e) { e.printStackTrace(); }} 完整源码
在这里,我们给出手动实现的ThreadPol线程池的完整源代码,如下所示。 package io.binghe.thread.pool;import java.util.ArrayList;import java.util.List;import java.util.concurrent.BlockingQueue;import java.util.concurrent.LinkedBlockingQueue;import java.util.stream.IntStream;/** * @author binghe * @version 1.0.0 * @description 自定义线程池 */public class ThreadPool { ///默认情况下阻塞队列的大小 private static final int DEFAULT_WORKQUEUE_SIZE = 5; ///模拟实际线程池使用阻塞队列来实现生产者-消费者模式 private BlockingQueue
是的,我们只用了几十行Java代码就实现了极简版的Java线程池。是的,这个极简版的Java线程池代码反映了Java线程池的核心原理。
接下来,我们将测试这个极简版的Java线程池。编制测试程序
测试程序也比较简单,即通过在main()方法中调用ThreadPol类的结构方法,将其传输到线程池的大小,创建ThreadPol类的实例,然后循环10次调用ThreadPol类的execute()方法,向线程池提交的任务是打印当前线程的名称--->> Hello ThreadPool。
整体测试代码如下所示。 package io.binghe.thread.pool.test;import io.binghe.thread.pool.ThreadPool;import java.util.stream.IntStream;/** * @author binghe * @version 1.0.0 * @description 测试自定义线程池 */public class ThreadPoolTest { public static void main(String[] args){ ThreadPool threadPool = new ThreadPool(10); IntStream.range(0, 10).forEach((i) -> { threadPool.execute(() -> { System.out.println(Thread.currentThread().getName() + "--->> Hello ThreadPool"); }); }); }}
接下来,运行ThreadPoltestmain()方法,输出以下信息。 Thread-0--->> Hello ThreadPoolThread-9--->> Hello ThreadPoolThread-5--->> Hello ThreadPoolThread-8--->> Hello ThreadPoolThread-4--->> Hello ThreadPoolThread-1--->> Hello ThreadPoolThread-2--->> Hello ThreadPoolThread-5--->> Hello ThreadPoolThread-9--->> Hello ThreadPoolThread-0--->> Hello ThreadPool
到目前为止,我们已经开发了自定义的Java线程池。总结
事实上,线程池的核心原理并不复杂。只要我们耐心分析,深入了解线程池的核心本质,你就会发现线程池的设计是如此优雅。我希望通过这个手写线程池的小例子,你能更好地理解线程池的核心原理。
点击关注,第一次了解华为云新技术~