使用Executors工厂方法创建线程池是一种简单快捷的方式,适用于一些常见的线程池需求。以下是几个示例,演示如何使用Executors工厂方法创建不同类型的线程池:
这种类型的线程池会一直保持固定数量的线程在池中,不会自动回收线程。适用于需要限制同时执行的任务数量的场景。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FixedThreadPoolExample {
public static void main(String[] args) {
int numThreads = 5;
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
// 提交任务到线程池
for (int i = 0; i < 10; i++) {
executor.submit(new MyRunnable(i));
}
executor.shutdown(); // 关闭线程池
}
}
缓存线程池会根据需要创建新的线程,如果线程池中的线程空闲时间超过指定的时间,则会被回收。适用于任务数量不确定,且需要自动调整线程数的场景。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CachedThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
// 提交任务到线程池
for (int i = 0; i < 10; i++) {
executor.submit(new MyRunnable(i));
}
executor.shutdown(); // 关闭线程池
}
}
单线程线程池只有一个工作线程,适用于需要按顺序执行任务的场景。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SingleThreadExecutorExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
// 提交任务到线程池
for (int i = 0; i < 10; i++) {
executor.submit(new MyRunnable(i));
}
executor.shutdown(); // 关闭线程池
}
}
定时任务线程池用于执行定时任务和周期性任务。
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledThreadPoolExample {
public static void main(String[] args) {
int numThreads = 3;
ScheduledExecutorService executor = Executors.newScheduledThreadPool(numThreads);
// 延迟1秒后执行任务
executor.schedule(new MyRunnable(1), 1, TimeUnit.SECONDS);
// 延迟2秒后,每3秒执行一次任务
executor.scheduleAtFixedRate(new MyRunnable(2), 2, 3, TimeUnit.SECONDS);
// 关闭线程池
executor.shutdown();
}
}
在这些示例中,MyRunnable是一个实现了Runnable接口的自定义任务类。创建线程池后,使用submit方法将任务提交给线程池进行执行,并最终调用shutdown方法关闭线程池。
这些Executors工厂方法提供了一些常见的线程池类型,但在某些情况下,可能需要更精细的线程池配置,这时可以考虑手动创建ThreadPoolExecutor。
手动创建 ThreadPoolExecutor 允许对线程池的各种参数进行更精细的配置,以满足特定的需求。以下是一个示例,演示如何手动创建 ThreadPoolExecutor:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ManualThreadPoolExecutorExample {
public static void main(String[] args) {
int corePoolSize = 5;
int maxPoolSize = 10;
long keepAliveTime = 60; // 60秒
TimeUnit timeUnit = TimeUnit.SECONDS;
BlockingQueue workQueue = new LinkedBlockingQueue<>();
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize, maxPoolSize, keepAliveTime, timeUnit, workQueue
);
// 提交任务到线程池
for (int i = 0; i < 10; i++) {
executor.submit(new MyRunnable(i));
}
executor.shutdown(); // 关闭线程池
}
}
class MyRunnable implements Runnable {
private int id;
public MyRunnable(int id) {
this.id = id;
}
@Override
public void run() {
System.out.println("Task " + id + " is running on thread " + Thread.currentThread().getName());
}
}
在这个示例中,手动创建了一个 ThreadPoolExecutor,并配置了核心线程数、最大线程数、线程空闲时间等参数。然后,使用 submit 方法将任务提交给线程池进行执行,并最终调用 shutdown 方法关闭线程池。
注意,BlockingQueue 参数用于指定任务队列,用来存储等待执行的任务。在这里,使用了 LinkedBlockingQueue,也可以选择其他的实现,如 ArrayBlockingQueue、PriorityBlockingQueue 等,以适应不同的需求。
手动创建 ThreadPoolExecutor 允许更精细地控制线程池的行为,但也需要更多的配置和管理。在选择线程池类型和参数时,应根据应用的特性和需求进行调整。
ForkJoinPool 是 Java 提供的用于支持分治任务的线程池实现。它特别适用于能够将任务拆分成更小的子任务,并且这些子任务可以并行执行的情况。以下是一个使用 ForkJoinPool 创建线程池的示例:
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
public class ForkJoinPoolExample {
public static void main(String[] args) {
ForkJoinPool forkJoinPool = new ForkJoinPool();
MyRecursiveAction task = new MyRecursiveAction(0, 10);
forkJoinPool.invoke(task);
forkJoinPool.shutdown();
}
}
class MyRecursiveAction extends RecursiveAction {
private static final int THRESHOLD = 2; // 阈值,小于该值就不再分解任务
private int start;
private int end;
public MyRecursiveAction(int start, int end) {
this.start = start;
this.end = end;
}
@Override
protected void compute() {
if (end - start <= THRESHOLD) {
// 执行任务逻辑
for (int i = start; i <= end; i++) {
System.out.println("Task is running on thread " + Thread.currentThread().getName() + ": " + i);
}
} else {
// 分解任务
int mid = (start + end) / 2;
MyRecursiveAction left = new MyRecursiveAction(start, mid);
MyRecursiveAction right = new MyRecursiveAction(mid + 1, end);
invokeAll(left, right);
}
}
}
在这个示例中,首先创建了一个 ForkJoinPool 实例,然后定义了一个继承自 RecursiveAction 的 MyRecursiveAction 类,用于表示要执行的分治任务。在 compute 方法中,首先检查任务是否足够小,如果是,则执行任务逻辑;否则,将任务分解为两个子任务并使用 invokeAll 方法并行执行。
ForkJoinPool 会根据任务的大小和可用线程数来动态地调度任务的执行,以获得最佳的并行性能。在实际使用中,可以根据任务的特性和复杂度调整阈值,以及分解和执行子任务的逻辑。
注意,ForkJoinPool 适用于能够利用分治并行计算的场景,如递归问题的解决和并行计算任务。
ScheduledThreadPoolExecutor 是 ThreadPoolExecutor 的子类,专门用于创建带有定时任务功能的线程池。它可以执行定时任务和周期性任务。以下是一个使用 ScheduledThreadPoolExecutor 创建线程池的示例:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledThreadPoolExecutorExample {
public static void main(String[] args) {
int numThreads = 3;
ScheduledExecutorService executor = Executors.newScheduledThreadPool(numThreads);
// 延迟1秒后执行任务
executor.schedule(new MyRunnable(1), 1, TimeUnit.SECONDS);
// 延迟2秒后,每3秒执行一次任务
executor.scheduleAtFixedRate(new MyRunnable(2), 2, 3, TimeUnit.SECONDS);
// 关闭线程池
executor.shutdown();
}
}
class MyRunnable implements Runnable {
private int id;
public MyRunnable(int id) {
this.id = id;
}
@Override
public void run() {
System.out.println("Task " + id + " is running on thread " + Thread.currentThread().getName());
}
}
在这个示例中,使用 Executors.newScheduledThreadPool() 方法创建了一个 ScheduledExecutorService,然后使用 schedule 方法在指定的延迟时间后执行一次任务,使用 scheduleAtFixedRate 方法在指定的延迟时间后开始执行任务,并且每隔一段时间重复执行。
ScheduledThreadPoolExecutor 可以满足定时任务和周期性任务的需求,它能够自动调度任务的执行。当任务执行时间超过任务间隔时间时,ScheduledThreadPoolExecutor 会等待当前任务完成后再启动下一个任务。这种特性对于需要保证任务执行间隔的场景非常有用。
许多第三方库都提供了对 ThreadPoolExecutor 的封装,以便更方便地创建和管理线程池。其中一个常用的库是 Apache Commons Lang 中的 ThreadPoolExecutor,它提供了一些额外的功能和配置选项。以下是一个使用 Apache Commons Lang 的 ThreadPoolExecutor 封装库的示例:
首先,确保已经将 Apache Commons Lang 库添加到项目中。然后,你可以使用 org.apache.commons.lang3.concurrent.BasicThreadFactory 来创建线程池。下面是示例代码:
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThirdPartyThreadPoolExample {
public static void main(String[] args) {
int numThreads = 3;
BasicThreadFactory factory = new BasicThreadFactory.Builder()
.namingPattern("my-pool-%d")
.daemon(true)
.build();
ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(
numThreads, factory);
// 延迟1秒后执行任务
executor.schedule(new MyRunnable(1), 1, TimeUnit.SECONDS);
// 延迟2秒后,每3秒执行一次任务
executor.scheduleAtFixedRate(new MyRunnable(2), 2, 3, TimeUnit.SECONDS);
// 关闭线程池
executor.shutdown();
}
}
class MyRunnable implements Runnable {
private int id;
public MyRunnable(int id) {
this.id = id;
}
@Override
public void run() {
System.out.println("Task " + id + " is running on thread " + Thread.currentThread().getName());
}
}
在这个示例中,使用 BasicThreadFactory 来配置线程池。通过设置不同的属性,可以定制线程名、守护线程属性等。然后,使用 ScheduledThreadPoolExecutor 创建一个带有定时任务功能的线程池,并使用 schedule 和 scheduleAtFixedRate 方法添加定时任务。
使用第三方库的线程池封装可以帮助更方便地创建和管理线程池,以及提供一些额外的功能选项。