线程池源码分析

本文深入探讨Java线程池的继承结构,从Executor接口开始,逐步讲解ExecutorService和AbstractExecutorService,重点分析ThreadPoolExecutor的关键属性如核心线程数、最大线程数、工作队列和拒绝策略,并解析execute方法的工作流程。
摘要由CSDN通过智能技术生成

一、线程池继承结构

二、Executor接口

public interface Executor {

    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     *
     * @param command the runnable task
     * @throws RejectedExecutionException if this task cannot be
     * accepted for execution
     * @throws NullPointerException if command is null
     */
    void execute(Runnable command);
}

Executor接口位于最顶层,只有一个抽象方法,在ThreadPoolExecutor类中给出了具体实现。该方法用于提交一个任务,但任务何时执行、由哪个线程执行是不确定的,替代了以往new Thread(new (RunnableTask())).start()的方法,将任务的提交、调度、执行解耦。该方法没有返回值,因此无法判断任务是否成功执行。

三、ExecutorService接口

public interface ExecutorService extends Executor {

	// 启动一个关闭命令,已提交的任务执行完后就关闭,同时不接收新任务
    // 如果已经关闭该方法调用无其他作用
    void shutdown();

	// 试图停止正在执行的任务,不再接受新的任务,返回等待执行的任务列表
	// 终止线程的方法是通过Thread.interrupt()实现的,该方法的成功执行是有条件的,
	// 即当线程是因sleep、wait、join阻塞时当线程因sleep、wait、join阻塞时,否则调用interrupt()方法不能中断线程,
	// 所以线程池可能不能立即关闭,可能要等任务执行完才能关闭
    List<Runnable> shutdownNow();

    // 线程池是否已关闭
    boolean isShutdown();

	// 在调用shutdown()或shutdownNow()后,是否所有任务均执行完毕,是的话返回true
	// 该方法要在shutdown()或shutdownNow()调用后且满足条件才能返回true
    boolean isTerminated();

	// timeout:超时时间,unit:单位
	// 常与shutdown()搭配使用,判断调用shutdown()后,线程池等待正在执行的线程执行完毕后关闭是否超时boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

    // 用于提交一个任务,并且有返回值,可通过future判断任务是否执行成功
    <T> Future<T> submit(Callable<T> task);
	<T> Future<T> submit(Runnable task, T result);
	Future<?> submit(Runnable task);

    // 批量提交任务,所有任务完成后返回future的一个list
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;
	<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;

    // 批量提交任务,当提交的任务有一个执行完毕就可返回,返回的是执行完毕的任务的结果
    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;
	<T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

ExecutorService接口继承了Executor接口,提供了更多的功能,一般定义一个线程池时使用该接口。

四、AbstractExecutorService类

AbstractExecutorService抽象类派生自ExecutorService接口,对该接口的部分方法给出了实现。

1. newTaskFor方法

// 将任务包装成FutureTask,并返回一个RunnableFuture对象,可通过该对象获取执行结果
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
	return new FutureTask<T>(runnable, value);
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
	return new FutureTask<T>(callable);
}

2. submit方法

用于提交一个任务,并且有返回值,可用于判断任务是否执行成功

// 任务执行成功调用Future的get()方法返回null
public Future<?> submit(Runnable task) {
	if (task == null) throw new NullPointerException(); // 若任务为null则抛出异常
	RunnableFuture<Void> ftask = newTaskFor(task, null); // 将任务包装成FutureTask
	execute(ftask); // 由子类提供具体实现
	return ftask;
}

// 任务执行成功调用Future的get()方法返回给定结果
public <T> Future<T> submit(Runnable task, T result) {
	if (task == null) throw new NullPointerException();
	RunnableFuture<T> ftask = newTaskFor(task, result);
	execute(ftask);
	return ftask;
}

// 任务执行成功调用Future的get()方法返回给定结果
public <T> Future<T> submit(Callable<T> task) {
	if (task == null) throw new NullPointerException();
	RunnableFuture<T> ftask = newTaskFor(task);
	execute(ftask);
	return ftask;
}

3. doInvokeAny方法

// 调用invokeAny()时的主要机制
// tasks:任务集合,timed:是否设置超时机制,nanos:超时时间
private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
						  boolean timed, long nanos)
	throws InterruptedException, ExecutionException, TimeoutException {
	if (tasks == null)
		throw new NullPointerException();
	int ntasks = tasks.size(); // 任务的数量
	if (ntasks == 0)
		throw new IllegalArgumentException();
	ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
	
	// 将执行器包装为ExecutorCompletionService,使得每个任务执行完后,将结果保存在completionQueue中
	ExecutorCompletionService<T> ecs =
		new ExecutorCompletionService<T>(this);

	// 为了提高效率,要在提交新任务之前检查之前提交的任务是否执行完成
	try {
		// 记录执行异常,使得当我们不能成功获取执行结果时抛出最后得到的一个异常
		ExecutionException ee = null;
		final long deadline = timed ? System.nanoTime() + nanos : 0L;
		Iterator<? extends Callable<T>> it = tasks.iterator();

		// 首先提交一个任务,任务数减1,active(正在执行的任务数)加1
		futures.add(ecs.submit(it.next()));
		--ntasks;
		int active = 1;

		for (;;) {
			Future<T> f = ecs.poll(); // 从completionQueue中取出一个Future
			if (f == null) { // 若为空即当前没有任务执行完成
				if (ntasks > 0) { // 若还有未执行任务则提交一个新任务
					--ntasks;
					futures.add(ecs.submit(it.next()));
					++active;
				}
				else if (active == 0) // 若未执行和执行任务数均为0则跳出循环
					break;
				else if (timed) { // 若所有任务已提交,且无任务执行完成,且设置了超时机制
					f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
					if (f == null) // 若在时间内未有任务完成则抛出异常
						throw new TimeoutException();
					nanos = deadline - System.nanoTime();
				}
				else // 所有任务已提交,没有任务执行完成,没有设置超时机制
					f = ecs.take(); // 阻塞直至有任务执行完成
			}
			
			if (f != null) { // 有任务执行完成
				--active; // 执行任务数减1
				try {
					return f.get(); // 返回执行结果
				} catch (ExecutionException eex) {
					ee = eex;
				} catch (RuntimeException rex) {
					ee = new ExecutionException(rex);
				}
			}
		}

		if (ee == null)
			ee = new ExecutionException();
		throw ee;

	} finally {
		for (int i = 0, size = futures.size(); i < size; i++) // 方法退出之前取消其他任务
			futures.get(i).cancel(true);
	}
}

4. invokeAny方法

// 提交任务集合,当有一个任务完成后则返回
public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
	throws InterruptedException, ExecutionException {
	try {
		return doInvokeAny(tasks, false, 0);
	} catch (TimeoutException cannotHappen) {
		assert false;
		return null;
	}
}

public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
					   long timeout, TimeUnit unit)
	throws InterruptedException, ExecutionException, TimeoutException {
	return doInvokeAny(tasks, true, unit.toNanos(timeout));
}

5. invokeAll方法

public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
	throws InterruptedException {
	if (tasks == null)
		throw new NullPointerException();
	ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
	boolean done = false;
	try {
		for (Callable<T> t : tasks) {
			RunnableFuture<T> f = newTaskFor(t); // 将每个任务包装成RunnableFuture
			futures.add(f);
			execute(f); // 提交任务
		}
		for (int i = 0, size = futures.size(); i < size; i++) {
			Future<T> f = futures.get(i);
			if (!f.isDone()) {
				try {
					f.get(); // 是一个阻塞的方法,直到获取正确的值或者抛出异常
				} catch (CancellationException ignore) {
				} catch (ExecutionException ignore) {
				}
			}
		}
		done = true;
		return futures;
	} finally {
		if (!done) // 若出现异常,取消其他正在执行的任务
			for (int i = 0, size = futures.size(); i < size; i++)
				futures.get(i).cancel(true);
	}
}

public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
	throws InterruptedException {
	if (tasks == null)
		throw new NullPointerException();
	long nanos = unit.toNanos(timeout);
	ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
	boolean done = false;
	try {
		for (Callable<T> t : tasks) // 将任务包装成FutureTask并放入列表
			futures.add(newTaskFor(t));

		final long deadline = System.nanoTime() + nanos;
		final int size = futures.size();

		// Interleave time checks and calls to execute in case
		// executor doesn't have any/much parallelism.
		for (int i = 0; i < size; i++) {
			execute((Runnable)futures.get(i)); // 提交任务
			nanos = deadline - System.nanoTime();
			if (nanos <= 0L) // 任务尚未提交完就超时
				return futures;
		}

		for (int i = 0; i < size; i++) {
			Future<T> f = futures.get(i);
			if (!f.isDone()) {
				if (nanos <= 0L) // 任务提交完了,但是存在执行超时的任务
					return futures;
				try {
					f.get(nanos, TimeUnit.NANOSECONDS);
				} catch (CancellationException ignore) {
				} catch (ExecutionException ignore) {
				} catch (TimeoutException toe) {
					return futures;
				}
				nanos = deadline - System.nanoTime();
			}
		}
		done = true;
		return futures;
	} finally {
		if (!done)
			for (int i = 0, size = futures.size(); i < size; i++)
				futures.get(i).cancel(true);
	}
}

五、ThreadPoolExecutor类

1. 关键属性:

  • corePoolSize:核心线程数,即使没有任务处理,核心线程也会一直存活。若当前线程数小于核心线程数时,即使有空闲线程,也会创建一个新的线程执行任务。
  • maximumPoolSize:最大线程数,即线程池允许创建的最大线程数。
  • keepAliveTime:空闲线程的保活时间,当线程空闲时间达到该值时,该线程会退出,直至线程数减至核心线程数。
  • unit:keepAliveTime的单位。
  • workQueue:工作队列,存放待提交的任务。
  • threadFactory:创建线程的工厂。
  • handler:当线程池已满而又有任务提交时采用的策略,具体Java 线程池的拒绝策略 RejectedExecutorHandler
// 构造方法
public ThreadPoolExecutor(int corePoolSize,
						  int maximumPoolSize,
						  long keepAliveTime,
						  TimeUnit unit,
						  BlockingQueue<Runnable> workQueue,
						  ThreadFactory threadFactory,
						  RejectedExecutionHandler handler) {
	if (corePoolSize < 0 ||
		maximumPoolSize <= 0 ||
		maximumPoolSize < corePoolSize ||
		keepAliveTime < 0)
		throw new IllegalArgumentException();
	if (workQueue == null || threadFactory == null || handler == null)
		throw new NullPointerException();
	this.acc = System.getSecurityManager() == null ?
			null :
			AccessController.getContext();
	this.corePoolSize = corePoolSize;
	this.maximumPoolSize = maximumPoolSize;
	this.workQueue = workQueue;
	this.keepAliveTime = unit.toNanos(keepAliveTime);
	this.threadFactory = threadFactory;
	this.handler = handler;
}

2. execute方法

public void execute(Runnable command) {
	if (command == null)
		throw new NullPointerException();
	int c = ctl.get();
	// 如果当前线程数少于核心线程数,添加一个新的线程,并将任务提交给该线程
	if (workerCountOf(c) < corePoolSize) {
		if (addWorker(command, true))
			return;
		c = ctl.get();
	}
	
	// 执行到此处,要么所有线程数大于等于核心线程数,要么addWorker失败
	// 若线程池处于running状态,则将任务放置到工作队列
	if (isRunning(c) && workQueue.offer(command)) {
		int recheck = ctl.get();
		// 再次检测线程池的状态,避免在上次检测后线程池被关闭
		// 若被关闭,则将任务从任务队列中移除并执行拒绝策略
		if (! isRunning(recheck) && remove(command))
			reject(command);
		// 若线程池处于running状态,且线程数为0,则创建一个新的线程
		else if (workerCountOf(recheck) == 0)
			addWorker(null, false);
	}
	// 若队列满了,则在线程数小于maximumPoolSize的情况下创建一个新线程
	// 若创建失败,则执行拒绝策略
	else if (!addWorker(command, false))
		reject(command);
}

 

 

 

参考:

1. 深度解读 java 线程池设计思想及源码实现 https://juejin.im/entry/59b232ee6fb9a0248d25139a#%E6%80%BB%E7%BB%93

2. 【Java8源码分析】线程池-Executor与ExecutorService的全面剖析 https://blog.csdn.net/linxdcn/article/details/72828362

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值