深入理解 Java 线程池

一、简介 什么是线程池

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。

为什么要用线程池

如果并发请求数量很多,但每个线程执行的时间很短,就会出现频繁的创建和销毁线程。如此一来,会大大降低系统的效率,可能频繁创建和销毁线程的时间、资源开销要大于实际工作的所需。

正是由于这个问题,所以有必要引入线程池。使用 线程池的好处 有以下几点:

降低资源消耗 - 通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

提高响应速度 - 当任务到达时,任务可以不需要等到线程创建就能立即执行。

提高线程的可管理性 - 线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。但是要做到合理的利用线程池,必须对其原理了如指掌。

二、Executor 框架

Executor 框架是一个根据一组执行策略调用,调度,执行和控制的异步任务的框架,目的是提供一种将”任务提交”与”任务如何运行”分离开来的机制。

核心 API 概述

Executor 框架核心 API 如下:

Executor - 运行任务的简单接口。

ExecutorService - 扩展了 Executor 接口。扩展能力:

支持有返回值的线程;

支持管理线程的生命周期。

ScheduledExecutorService - 扩展了 ExecutorService 接口。扩展能力:支持定期执行任务。

AbstractExecutorService - ExecutorService 接口的默认实现。

ThreadPoolExecutor - Executor 框架最核心的类,它继承了 AbstractExecutorService 类。

ScheduledThreadPoolExecutor - ScheduledExecutorService 接口的实现,一个可定时调度任务的线程池。

Executors - 可以通过调用 Executors 的静态工厂方法来创建线程池并返回一个 ExecutorService 对象。

深入理解 Java 线程池

Executor

Executor 接口中只定义了一个 execute 方法,用于接收一个 Runnable 对象。

public interface Executor { void execute(Runnable command); } ExecutorService

ExecutorService 接口继承了 Executor 接口,它还提供了 invokeAll、invokeAny、shutdown、submit 等方法。

public interface ExecutorService extends Executor { void shutdown(); List<Runnable> shutdownNow(); boolean isShutdown(); boolean isTerminated(); boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException; <T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task); <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; }

从其支持的方法定义,不难看出:相比于 Executor 接口,ExecutorService 接口主要的扩展是:

支持有返回值的线程 - sumbit、invokeAll、invokeAny 方法中都支持传入Callable 对象。

支持管理线程生命周期 - shutdown、shutdownNow、isShutdown 等方法。

ScheduledExecutorService

ScheduledExecutorService 接口扩展了 ExecutorService 接口。

它除了支持前面两个接口的所有能力以外,还支持定时调度线程。

public interface ScheduledExecutorService extends ExecutorService { public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit); public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit); public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit); public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit); }

其扩展的接口提供以下能力:

schedule 方法可以在指定的延时后执行一个 Runnable 或者 Callable 任务。

scheduleAtFixedRate 方法和 scheduleWithFixedDelay 方法可以按照指定时间间隔,定期执行任务。

三、ThreadPoolExecutor

java.uitl.concurrent.ThreadPoolExecutor 类是 Executor 框架中最核心的类。所以,本文将着重讲述一下这个类。

重要字段

ThreadPoolExecutor 有以下重要字段:

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); private static final int COUNT_BITS = Integer.SIZE - 3; private static final int CAPACITY = (1 << COUNT_BITS) - 1; // runState is stored in the high-order bits private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS;

参数说明:

ctl - 用于控制线程池的运行状态和线程池中的有效线程数量。它包含两部分的信息:

线程池的运行状态 (runState)

线程池内有效线程的数量 (workerCount)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyysjg.html