import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CustomThreadPool {
public static void main(String[] args) {
// 创建一个固定大小的线程池
int poolSize = 10;
ExecutorService executor = Executors.newFixedThreadPool(poolSize);
// 为线程池中的每个线程指定名称
for (int i = 0; i < poolSize; i++) {
executor.execute(() -> {
Thread.currentThread().setName("Thread-" + i);
// 这里可以执行你的任务代码
});
}
// 关闭线程池(这不会立即关闭,而是等待所有任务都完成)
executor.shutdown();
}
}
在上述代码中,我们使用了Executors.newFixedThreadPool来创建一个固定大小的线程池。然后,我们使用一个循环来为线程池中的每个线程执行任务,并在任务中为每个线程指定一个名称。最后,我们调用executor.shutdown()来关闭线程池。
请注意,线程的名称只是用于标识和调试目的,并不会影响线程的行为。另外,如果你想在任务执行期间获取线程的名称,你需要在适当的地方(例如在任务代码中)使用Thread.currentThread().getName()来获取它。
以下是一个自定义的ThreadPoolExecutor的示例代码,它设置了线程池的基本属性和参数:
import java.util.concurrent.*;
public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
// 重写方法,自定义线程池的行为
@Override
protected void beforeExecute(Thread t, Runnable r) {
// 在任务执行前执行的代码
System.out.println("Before executing task: " + r.toString());
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
// 在任务执行后执行的代码
System.out.println("After executing task: " + r.toString());
}
@Override
protected void terminated() {
// 线程池终止时执行的代码
System.out.println("ThreadPoolExecutor terminated.");
}
}
通过重写这些方法,你可以在任务执行的生命周期的不同阶段添加自定义的行为,以满足你的需求。
示例
上面自定义的CustomThreadPoolExecutor
是一个线程池的实现,你可以通过创建一个CustomThreadPoolExecutor
对象来创建一个线程池,并使用该线程池来执行任务。
以下是一个使用CustomThreadPoolExecutor
的示例代码:
import java.util.concurrent.*;
public class CustomThreadPoolExecutorExample {
public static void main(String[] args) {
// 创建一个CustomThreadPoolExecutor对象
CustomThreadPoolExecutor customThreadPoolExecutor = new CustomThreadPoolExecutor(
2, // 核心线程数
4, // 最大线程数
60L, // 保持活跃时间
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<Runnable>() // 等待队列
);
// 提交任务给线程池执行
for (int i = 0; i < 6; i++) {
customThreadPoolExecutor.execute(new Task(i));
}
// 关闭线程池
customThreadPoolExecutor.shutdown();
}
}
class Task implements Runnable {
private int taskId;
public Task(int taskId) {
this.taskId = taskId;
}
@Override
public void run() {
System.out.println("Task " + taskId + " is running.");
}
}
在这个示例中,我们首先创建了一个CustomThreadPoolExecutor
对象,并设置了它的核心线程数、最大线程数、保持活跃时间和等待队列。然后,我们通过调用execute()
方法向线程池提交了6个任务。每个任务是一个实现了Runnable
接口的Task
对象,它的run()
方法只是简单地输出一个消息。最后,我们调用shutdown()
方法关闭线程池。
在任务执行过程中,CustomThreadPoolExecutor
会自动管理线程的创建和销毁,并保证任务按照提交的顺序执行。同时,我们还重写了beforeExecute()
、afterExecute()
和terminated()
方法,分别在任务执行前、执行后和线程池终止时执行自定义的逻辑。例如,在beforeExecute()
方法中,我们可以输出任务的信息,以便观察任务的执行顺序。
ThreadPoolExecutor
中有以下几个重要的指标1:ThreadPoolExecutor
中的 ThreadPoolExecutor.getPoolSize()
, ThreadPoolExecutor.getActiveCount()
, ThreadPoolExecutor.getTaskCount()
, ThreadPoolExecutor.getCompletedTaskCount()
等方法。Thread.getState()
, Thread.getName()
, Thread.getStackTrace()
等方法获取线程的各个状态信息。下面是一个简单的示例程序,用于监控线程池的状态信息:
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
public class ThreadPoolMonitor implements Runnable {
private ThreadPoolExecutor threadPool;
private long interval;
private TimeUnit unit;
public ThreadPoolMonitor(ThreadPoolExecutor threadPool, long interval, TimeUnit unit) {
this.threadPool = threadPool;
this.interval = interval;
this.unit = unit;
}
@Override
public void run() {
while (true) {
// 获取线程池状态信息
int corePoolSize = threadPool.getCorePoolSize();
int maximumPoolSize = threadPool.getMaximumPoolSize();
int activeCount = threadPool.getActiveCount();
int completedTaskCount = threadPool.getCompletedTaskCount();
int taskCount = threadPool.getTaskCount();
long keepAliveTime = threadPool.getKeepAliveTime(TimeUnit.MILLISECONDS);
TimeUnit unit = threadPool.getKeepAliveTimeUnit();
String workQueue = threadPool.getQueue().getClass().getName();
ThreadFactory threadFactory = threadPool.getThreadFactory();
RejectedExecutionHandler rejectedExecutionHandler = threadPool.getRejectedExecutionHandler();
// 输出状态信息
System.out.println(new Date() + " CorePoolSize: " + corePoolSize + ", MaximumPoolSize: " + maximumPoolSize +
", ActiveCount: " + activeCount + ", CompletedTaskCount: " + completedTaskCount + ", TaskCount: " + taskCount +
", KeepAliveTime: " + keepAliveTime + " " + unit + ", WorkQueue: " + workQueue + ", ThreadFactory: " + threadFactory +
", RejectedExecutionHandler: " + rejectedExecutionHandler);
try {
// 休眠一段时间,等待下一次采集
Thread.sleep(interval);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
ThreadPoolMonitor monitor = new ThreadPoolMonitor(threadPool, 1000, TimeUnit.MILLISECONDS);
new Thread(monitor).start();
}
}
要获取达到最大线程数后被拒绝的线程数或异常数,可以通过线程池的 getRejectedExecutionHandler()
方法获取 RejectedExecutionHandler
对象,然后根据具体情况实现自定义的拒绝策略。
ThreadPoolExecutor.AbortPolicy
: 默认的拒绝策略,直接抛出 RejectedExecutionException
异常。ThreadPoolExecutor.CallerRunsPolicy
: 调用者线程运行被拒绝的任务,不抛出异常。ThreadPoolExecutor.DiscardPolicy
: 忽略被拒绝的任务,不保存,也不抛出异常。ThreadPoolExecutor.DiscardOldestPolicy
: 丢弃队列中最老的任务,然后尝试重新提交。ThreadPoolExecutor.WaitForTasksPolicy
: 等待当前任务队列的任务都完成后再执行被拒绝的任务。ThreadPoolExecutor.CallerRunsPolicy
如果以上策略都不满足需求,可以自定义实现 RejectedExecutionHandler
接口,根据具体需求进行处理。例如,可以统计被拒绝的线程数或异常数,或者将任务保存到数据库或文件等地方,以便后续处理。
ThreadPoolExecutor.CallerRunsPolicy是Java线程池中的一个拒绝策略,当线程池拒绝一个新任务时,它会调用该策略来处理被拒绝的任务。
当拒绝策略为CallerRunsPolicy时,线程池会调用执行者所在的线程来执行被拒绝的任务,也就是说,直接在调用execute方法的线程中运行被拒绝的任务。如果执行程序已关闭,则会丢弃该任务。这种策略会降低对于新任务提交速度,影响程序的整体性能。如果您的应用程序可以承受此延迟并且要求任何一个任务请求都要被执行,可以选择该策略。
以下是一个简单的示例代码,演示如何获取达到最大线程数后被拒绝的线程数:
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.RejectedExecutionHandler;
public class ThreadPoolMonitor implements Runnable {
private ThreadPoolExecutor threadPool;
private long interval;
private TimeUnit unit;
public ThreadPoolMonitor(ThreadPoolExecutor threadPool, long interval, TimeUnit unit) {
this.threadPool = threadPool;
this.interval = interval;
this.unit = unit;
}
@Override
public void run() {
while (true) {
// 获取线程池状态信息
int corePoolSize = threadPool.getCorePoolSize();
int maximumPoolSize = threadPool.getMaximumPoolSize();
int activeCount = threadPool.getActiveCount();
int completedTaskCount = threadPool.getCompletedTaskCount();
int taskCount = threadPool.getTaskCount();
long keepAliveTime = threadPool.getKeepAliveTime(TimeUnit.MILLISECONDS);
TimeUnit unit = threadPool.getKeepAliveTimeUnit();
String workQueue = threadPool.getQueue().getClass().getName();
ThreadFactory threadFactory = threadPool.getThreadFactory();
RejectedExecutionHandler rejectedExecutionHandler = threadPool.getRejectedExecutionHandler();
int rejectedCount = 0; // 被拒绝的线程数
if (rejectedExecutionHandler instanceof ThreadPoolExecutor.AbortPolicy) {
rejectedCount = ((ThreadPoolExecutor.AbortPolicy) rejectedExecutionHandler).getRejectedExecutionCount();
} else if (rejectedExecutionHandler instanceof ThreadPoolExecutor.CallerRunsPolicy) {
rejectedCount = ((ThreadPoolExecutor.CallerRunsPolicy) rejectedExecutionHandler).getRunCount();
} else if (rejectedExecutionHandler instanceof ThreadPoolExecutor.DiscardPolicy) {
rejectedCount = ((ThreadPoolExecutor.DiscardPolicy) rejectedExecutionHandler).getDiscardCount();
} else if (rejectedExecutionHandler instanceof ThreadPoolExecutor.DiscardOldestPolicy) {
rejectedCount = ((ThreadPoolExecutor.DiscardOldestPolicy) rejectedExecutionHandler).getDiscardCount();
} else if (rejectedExecutionHandler instanceof ThreadPoolExecutor.WaitForTasksPolicy) {
rejectedCount = ((ThreadPoolExecutor.WaitForTasksPolicy) rejectedExecutionHandler).getTaskCount();
}
System.out.println(new Date() + " CorePoolSize: " + corePoolSize + ", MaximumPoolSize: " + maximumPoolSize +
", ActiveCount: " + activeCount + ", CompletedTaskCount: " + completedTaskCount + ", TaskCount: " + taskCount +
", KeepAliveTime: " + keepAliveTime + " " + unit + ", WorkQueue: " + workQueue + ", ThreadFactory: " + threadFactory +
", RejectedExecutionHandler: " + rejectedExecutionHandler + ", RejectedCount: " + rejectedCount);
try {
// 休眠一段时间,等待下一次采集
Thread.sleep(interval);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
ThreadPoolMonitor monitor = new ThreadPoolMonitor(threadPool, 1000, TimeUnit.MILLISECONDS
}
指标 | 含义 |
---|---|
maximumPoolSize | 最大线程数,当线程池繁忙时最多可以拥有的线程数 |
corePoolSize | 核心线程数,线程池中始终保持的线程数 |
minimumPoolSize | 最小线程数,线程池中线程数的下限值 |
poolSize | 当前线程数,线程池中正在运行的线程数 |
activeCount | 活动线程数,当前正在执行任务的线程数 |
taskCount | 任务数,线程池中已提交的任务总数 |
completedTaskCount | 完成的任务数,线程池中已经完成的任务总数 |
largestPoolSize | 最大的线程数,线程池曾拥有的最大线程数 |
keepAliveTime | 空闲线程存活时间,当线程超过该时间没有任务时,就会被回收 |
TimeUnit | 时间单位,用于描述参数3的单位,如秒、毫秒等 |
BlockingQueue | 任务队列,用于保存待执行任务的容器 |
ThreadFactory | 线程工厂,用于创建线程池中线程的工厂方法,可以通过它来设置线程的命名规则、优先级和线程类型 |
RejectedExecutionHandler | 拒绝策略,当任务量超过线程池可以保存的最大任务数时,执行的策略 |
CompletableFuture 是 Java 8 引入的一个强大的并发工具,它允许你以异步的方式处理任务,并且可以方便地组合多个异步任务。ThreadPoolExecutor 则是 Java 提供的一个线程池工具,它可以根据需要创建和管理线程,以支持并发执行任务。
下面是一个使用 CompletableFuture 和 ThreadPoolExecutor 实现并发异步处理的示例:
import java.util.concurrent.*;
public class CompletableFutureWithThreadPool {
public static void main(String[] args) {
// 创建一个固定大小的线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // 核心线程数
10, // 最大线程数
60, // 线程空闲超过60秒则销毁
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<Runnable>() // 任务队列
);
// 使用 CompletableFuture 来执行异步任务
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
// 模拟一个耗时操作
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "任务1完成";
}, executor);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
// 模拟一个耗时操作
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "任务2完成";
}, executor);
CompletableFuture<Void> all = CompletableFuture.allOf(future1, future2);
all.thenRun(() -> {
System.out.println("所有任务都已完成");
executor.shutdown(); // 关闭线程池
});
}
}
在上面的示例中,我们首先创建了一个 ThreadPoolExecutor,并指定了其核心线程数、最大线程数、线程空闲超时时间以及任务队列。然后,我们使用 CompletableFuture.supplyAsync 方法来执行两个异步任务,这两个任务会使用我们创建的线程池来执行。每个异步任务都是一个耗时操作,模拟了某些需要长时间运行的任务。最后,我们使用 CompletableFuture.allOf 方法来等待两个异步任务都完成,当所有任务都完成后,我们输出一条消息并关闭线程池。
通过这个示例,你可以看到如何使用 CompletableFuture 和 ThreadPoolExecutor 来实现并发异步处理。你可以根据实际需求调整线程池的参数以及异步任务的逻辑。
注意
是的,对于一直在运行的线上业务流程,通常不需要显式地关闭线程池。线程池会自动管理线程的生命周期,根据需要创建和销毁线程。当提交任务到线程池时,线程池会根据其配置的参数决定是否创建新的线程来执行任务。如果当前线程数已经达到池中线程数的上限,则任务会等待,直到有空闲线程可用。
一般情况下,线程池会一直运行,直到没有任务提交或者显式地关闭线程池。即使没有任务提交,线程池中的线程也不会立即被销毁,而是会保持空闲状态,等待新的任务到来。
然而,需要注意的是,长时间运行的线程池可能会占用系统资源,并且如果存在长时间运行的任务,可能会阻塞其他任务的执行。因此,在设计和使用线程池时,应该根据业务需求和系统资源情况进行合理的配置和监控,以确保系统的稳定性和性能。
如果你的程序一直在运行,并且线程池已经调用了shutdown方法,那么线程池中的线程将不再接受新的任务。此时,如果你尝试提交新的任务给线程池,将会抛出RejectedExecutionException异常。
如果你希望在程序运行时能够暂停线程池的执行,而不是完全关闭线程池,你可以使用线程池的shutdown或shutdownNow方法。这两个方法都会停止接受新的任务,但shutdownNow方法会尝试停止所有正在执行的任务,而shutdown方法则会等待已提交的任务执行完毕后再停止。
如果你希望在程序运行时能够动态地调整线程池的大小或改变线程池的行为,可以考虑使用可扩展的线程池或配置更灵活的线程池实现,例如ForkJoinPool或ExecutorService的定制实现。这些线程池可以更好地适应不同的应用程序需求。
果你的程序一直在运行,并且线程池已经调用了shutdown方法,那么线程池中的线程将不再接受新的任务。此时,如果你尝试提交新的任务给线程池,将会抛出RejectedExecutionException异常。
如果你希望在程序运行时能够暂停线程池的执行,而不是完全关闭线程池,你可以使用线程池的shutdown或shutdownNow方法。这两个方法都会停止接受新的任务,但shutdownNow方法会尝试停止所有正在执行的任务,而shutdown方法则会等待已提交的任务执行完毕后再停止。
如果你希望在程序运行时能够动态地调整线程池的大小或改变线程池的行为,可以考虑使用可扩展的线程池或配置更灵活的线程池实现,例如ForkJoinPool或ExecutorService的定制实现。这些线程池可以更好地适应不同的应用程序需求。