Executor接口
java.util.concurrent包里面有一个接口Executor。这是执行已提交的Runnable任务的对象。该接口的目的是为了解耦任务提交和任务的实际执行(包括线程使用的细节、调度等)。该接口只定义了一个方法execute(Runnable command),用于将任务提交到执行器中并在未来某个时间执行。
直接用法:
package org.hbin.pool.interfaces;
import java.util.concurrent.Executor;
/**
* Description:
* Author: HaleyHu
* Date: 2025/1/14 10:45
*/
public class ExecutorTest {
static class RunnableTask1 implements Runnable {
@Override
public void run() {
}
}
static class RunnableTask2 implements Runnable {
@Override
public void run() {
}
}
public static void main(String[] args) {
Executor anExecutor = new Executor() {
@Override
public void execute(Runnable command) {
// do something
}
};
Executor executor = anExecutor;
executor.execute(new RunnableTask1());
executor.execute(new RunnableTask2());
}
}
不过,Executor接口并没有严格地要求执行是异步的。简单情况,执行程序可以在调用者线程中立即运行已提交的任务:
import java.util.concurrent.Executor;
public class DirectExecutor implements Executor {
@Override
public void execute(Runnable command) {
command.run();
}
}
更典型的是,任务在调用者线程之外的某个线程中执行的。以下执行程序为每个任务生成一个新线程。
import java.util.concurrent.Executor;
public class ThreadPerTaskExecutor implements Executor {
@Override
public void execute(Runnable command) {
new Thread(command).start();
}
}
许多Executor实现对任务的调度方式和时间施加了某种限制。下面的执行器将任务提交序列化到第二个执行器,说明了复合执行器。
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.Executor;
public class SerialExecutor implements Executor {
private Executor executor;
private Queue<Runnable> tasks;
private Runnable active;
public SerialExecutor(Executor executor) {
this.executor = executor;
this.tasks = new ArrayDeque<>();
}
@Override
public void execute(Runnable command) {
tasks.offer(new Runnable() {
@Override
public void run() {
try {
command.run();
} finally {
scheduleNext();
}
}
});
if(active == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if((active = tasks.poll()) != null) {
executor.execute(active);
}
}
}
ExecutorService
一个执行器,它提供管理终止的方法,以及可以生成Future以跟踪一个或多个异步任务进度的方法。
ExecutorService可以关闭,这将导致它拒绝新任务。ExecutorService提供了两种不同的方法来关闭。shutdown()方法将允许先前提交的任务在终止前执行,而shutdownNow()方法则阻止等待的任务启动并尝试停止当前正在执行的任务。终止后,执行者没有正在执行的任务,没有等待执行的任务并且不能提交新任务。应关闭未使用的ExecuteService,以便回收其资源。
方法submit通过创建并返回一个Future来扩展基本方法Executor.execute(Runnable),该Future可用于取消执行和/或等待完成。方法invokeAny和invokeAll执行最常用的批量执行形式,执行一组任务,然后等待至少一个或全部任务完成。(类ExecutorCompletionService可用于编写这些方法的自定义变体。)
Executors类为此包中提供的执行器服务提供工厂方法。
使用示例
这是一个网络服务的草图,其中线程池中的线程为传入请求提供服务。它使用预配置的Executors.newFixedThreadPool(int)工厂方法:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class NetworkService implements Runnable {
private final ServerSocket socket;
private final ExecutorService pool;
public NetworkService(int port, int poolSize) throws IOException {
socket = new ServerSocket(port);
pool = Executors.newFixedThreadPool(poolSize);
}
@Override
public void run() {
try {
while(true) {
pool.execute(new Handler(socket.accept()));
}
} catch (IOException e) {
pool.shutdown();
}
}
}
class Handler implements Runnable {
private final Socket socket;
public Handler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
// read and service request on socket
}
}
常用方法:
submit()
提交任务到线程池中执行,并返回一个Future对象,它可以用于判断任务是否完成,以及获取任务的执行结果。shutdown()
关闭线程池。调用该方法后,线程池不再接收新的任务,但会继续执行已提交的任务直到所有任务执行完毕。shutdownNow()
立即关闭线程池。调用该方法后,线程池会立即中断所有正在执行的任务,并返回一个列表,包含所有未执行的任务。isShutdown()
线程池是否关闭isTerminated()
线程池中的所有任务是否已经执行完毕awaitTermination()
等待线程池中的所有任务全部执行完毕。该方法会阻塞当前线程,直到所有任务全部执行完毕或等待超时。invokeAll()invokeAny()
ScheduledExecutorService
ScheduledExecutorService是Java中用于调度任务的接口,它是ExecutorService的子接口,扩展了线程池的功能,允许在预定的时间执行任务,也可以周期性地重复执行任务。ScheduledExecutorService的设计初衷是为了解决Timer和TimerTask的缺陷,提供更灵活和可靠的定时调度功能。
常用方法:
schedule(Runnable command, long delay, TimeUnit unit)
在给定的延迟之后运行命令一次。schedule(Callable<V> callable, long delay, TimeUnit unit)
在给定的延迟之后执行有返回值的任务一次。scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
在指定的初始延迟后开始执行任务,并按照固定的时间间隔重复执行。当任务的执行时长大于周期,那么下一个任务将在当前任务执行完成后马上执行。scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
在指定的初始延迟后开始执行任务,并且在每次执行完成后,等待固定的延迟时间再执行下一次。
AbstractExecutorService
它是一个抽象类,实现了ExecutorService接口,提供了线程池的基本实现。它是Java Executor框架的核心类,提供了线程池的基本操作,如提交任务、管理线程池、执行任务等。自定义执行器服务可以扩展AbstractExecutorService并覆盖其方法以提供自己的实现。这使开发人员可以创建适合其特定需求的执行器服务。
ThreadPoolExecutor
ThreadPoolExecutor使用int的高3位来表示线程池状态,低29位标识线程数量。
public class ThreadPoolExecutor extends AbstractExecutorService {
/**
* The main pool control state, ctl, is an atomic integer packing
* two conceptual fields
* workerCount, indicating the effective number of threads
* runState, indicating whether running, shutting down etc
*
* In order to pack them into one int, we limit workerCount to
* (2^29)-1 (about 500 million) threads rather than (2^31)-1 (2
* billion) otherwise representable. If this is ever an issue in
* the future, the variable can be changed to be an AtomicLong,
* and the shift/mask constants below adjusted. But until the need
* arises, this code is a bit faster and simpler using an int.
*
* The workerCount is the number of workers that have been
* permitted to start and not permitted to stop. The value may be
* transiently different from the actual number of live threads,
* for example when a ThreadFactory fails to create a thread when
* asked, and when exiting threads are still performing
* bookkeeping before terminating. The user-visible pool size is
* reported as the current size of the workers set.
*
* The runState provides the main lifecycle control, taking on values:
*
* RUNNING: Accept new tasks and process queued tasks
* SHUTDOWN: Don't accept new tasks, but process queued tasks
* STOP: Don't accept new tasks, don't process queued tasks,
* and interrupt in-progress tasks
* TIDYING: All tasks have terminated, workerCount is zero,
* the thread transitioning to state TIDYING
* will run the terminated() hook method
* TERMINATED: terminated() has completed
*
* The numerical order among these values matters, to allow
* ordered comparisons. The runState monotonically increases over
* time, but need not hit each state. The transitions are:
*
* RUNNING -> SHUTDOWN
* On invocation of shutdown(), perhaps implicitly in finalize()
* (RUNNING or SHUTDOWN) -> STOP
* On invocation of shutdownNow()
* SHUTDOWN -> TIDYING
* When both queue and pool are empty
* STOP -> TIDYING
* When pool is empty
* TIDYING -> TERMINATED
* When the terminated() hook method has completed
*
* Threads waiting in awaitTermination() will return when the
* state reaches TERMINATED.
*
* Detecting the transition from SHUTDOWN to TIDYING is less
* straightforward than you'd like because the queue may become
* empty after non-empty and vice versa during SHUTDOWN state, but
* we can only terminate if, after seeing that it is empty, we see
* that workerCount is 0 (which sometimes entails a recheck -- see
* below).
*/
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;
}
| 状态名 | 高3位 | 接收新任务 | 处理阻塞任务队列 | 说明 |
|---|---|---|---|---|
| RUNNING | 111 | Y | Y | |
| SHUTDOWN | 000 | N | Y | 不会接收新任务,但会处理阻塞队列剩余任务 |
| STOP | 001 | N | N | 会中断正在执行的任务,并抛弃阻塞队列任务 |
| TIDYING | 010 | - | - | 任务全执行完毕,活动线程为0即将进入终结 |
| TERMINATED | 011 | - | - | 终结状态 |
从数值上看,RUNNING<SHUTDOWN<STOP<TIDYING<TERMINATED
这些信息存储在一个原子变量ctl中,目的是将线程池状态与线程个数合二为一,这样就可以用一次cas原子操作进行赋值。
170万+

被折叠的 条评论
为什么被折叠?



