最近在写Java程序的时候,接触到一些多线程方面的东西,用到了Java中的线程池。JDK中对线程池的支持比较完善,在java.util.concurrent包中,用ThreadPoolExecuter类表示一个线程池,同时还有一个Executor类扮演着线程池工厂的角色。例如:
代码如下 | 复制代码 |
public static ExecutorService newFixedThreadPool(int nThreads) public static ExecutorService newSingleThreadExecutor() public static ExecutorService newCachedThreadPool() ... |
这些工厂方法,从本质上,都是调用了ThreadPoolExecutor类的构造函数:
代码如下 | 复制代码 |
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) |
参数含义如下:
corePoolSize:线程池中应该保持的线程数量,即使线程空闲
maximumPoolSize:线程池中最大线程的数量
keepAliveTime:当线程数量大于corePoolSize时,指定空闲线程存在多久会被销毁
unit:keepAliveTime的单位
workQueue:任务队列,被提交但还没有执行
threadFactory:线程工厂
handler:拒绝策略
实现思路
从ThreadPoolExecutor的构造函数中,我们大概知道实现一个线程池需要哪些东西,如果完全按照构造函数中的参数来的话,太麻烦,有太多地方需要考虑,因此实现一个简单版的。
首先需要考虑线程池中存放多少线程。可以简单用一个变量来指定,并且这些线程要放在一个容器里,便于销毁,也便于知道他们的状态。
然后我们要考虑一个作为任务队列的容器。假如线程池中有5个线程,如果5个线程都处于工作状态的话,这时候送来的任务就需要放在任务队列中等待。
最后是线程池中工作线程的形式。工作线程在创建时开始就应该启动,其所做的工作主要是:从任务队列中取出任务-执行任务这样的无限循环。
工作线程的一种实现方式:
代码如下 | 复制代码 |
class WorkerThread extends Thread { private Boolean isRunning = true; public void close() { isRunning = false; } public void run() { |
WorkerThread是线程池的内部类,其中,taskQueue是任务队列,这里采用了BlockingQueue接口的一种实现,其put和take方法都是阻塞的。提交任务和销毁线程池如下:
代码如下 | 复制代码 |
public void submit(Runnable task) { if (currentWorking() < limits) { WorkerThread worker = new WorkerThread(); worker.start(); workers.add(worker); } try { taskQueue.put(task); } catch (InterruptedException e) { e.printStackTrace(); } } public void destroy() { |
完整代码在这里。
代码如下 | 复制代码 |
import java.util.ArrayList; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; /** private int limits; SimpleThreadPool(int nums) { private int currentWorking() { public void submit(Runnable task) { public void destroy() { class WorkerThread extends Thread { public void close() { public void run() { public static void main(String[] args) { class test implements Runnable { public test(String str) { id = str; } public void run() { |
线程池看似简单,其实很复杂,因为如果真要到一个应用级别的话,要考虑的东西还有很多,例如何时该启动一个线程,何时线程应该中止与挂起,任务队列的阻塞与超时,任务拒绝策略,线程生命周期等。至于本文实现的线程池