文章目录
概要
使用线程池
的过程中,直接使用 new
关键字来创建线程(例如 new Thread()
)是不推荐的做法。这是因为直接创建线程的方式存在一些缺点,而通过线程池可以更有效地管理线程资源,提升应用程序的性能和稳定性。
直接创建线程的缺点
a. 资源消耗大
每次创建一个新线程都需要分配系统资源,尤其是内存资源。频繁创建和销毁线程会导致系统资源的浪费
,并可能引起性能问题
。
b. 线程管理困难
直接创建的线程在使用完之后需要手动管理其生命周期。如果没有正确地管理,可能会导致线程泄漏或其他问题,例如过多的线程占用系统资源。
c. 难以控制并发数量
如果不加控制地创建线程,系统可能会因为过多的并发线程而陷入崩溃状态。线程数的增加会导致上下文切换的开销增大,从而影响系统性能。
使用线程池的优势
a. 资源复用
线程池在初始化时会创建一定数量的线程,这些线程可以复用
,而不需要每次都创建新的线程,从而减少了资源消耗。
b. 简化线程管理
线程池会自动管理线程的生命周期,开发者只需要提交任务即可,不需要关心线程的创建和销毁,减少了代码复杂度和错误率。
c. 控制并发数量
线程池可以通过配置最大线程数来控制并发线程的数量,避免了系统因为线程过多而崩溃的问题。
创建线程池给 Spring 管理—示例
以下是一个在工作中常用的、由Spring管理的线程池配置和使用的完整案例。这段代码展示了如何在Spring Boot应用中创建和配置线程池,并使用它来执行异步任务。
创建线程池配置类
通过创建一个配置类来定义线程池:
@Configuration
public class ThreadPoolConfig {
/**
* 定义一个名为 "taskExecutor" 的线程池Bean
*/
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
// 创建ThreadPoolTaskExecutor实例
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数,即线程池在闲置状态下的最小线程数
executor.setCorePoolSize(5);
// 设置最大线程数,即线程池在繁忙状态下的最大线程数
executor.setMaxPoolSize(10);
// 设置队列容量,当有超过核心线程数的任务提交时,这些任务会被放在队列中等待执行
executor.setQueueCapacity(25);
// 设置线程名前缀,方便在日志和监控中区分线程池中的线程
executor.setThreadNamePrefix("MyThreadPool-");
// 初始化线程池
executor.initialize();
// 返回配置好的线程池实例
return executor;
}
}
使用线程池
在Spring Bean中注入线程池并使用它来执行任务:
@Service
public class MyService {
//@Async("taskExecutor"):这个注解表示该方法将在异步执行。
//"taskExecutor"是我们定义的线程池名称,这意味着这个方法将由taskExecutor线程池中的线程来执行,而不是由调用线程执行。
//这个机制允许任务在后台执行,从而不会阻塞调用者的线程。
@Async("taskExecutor")
public CompletableFuture<String> executeTask(String taskName) {
System.out.println(Thread.currentThread().getName() + " - Executing task: " + taskName);
// 模拟任务处理
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return CompletableFuture.completedFuture("Task " + taskName + " completed");
}
}
启用异步支持
在Spring配置类中启用异步方法调用:
@Configuration
@EnableAsync
public class AsyncConfig {
}
创建控制器调用服务
在控制器中调用服务方法来执行任务:
@RestController
public class MyController {
@Autowired
private MyService myService;
@GetMapping("/execute")
public String executeTask(@RequestParam String taskName) {
CompletableFuture<String> future = myService.executeTask(taskName);
return "Task " + taskName + " is being executed.";
}
}
运行应用
确保你的Spring Boot应用程序可以正常运行。启动应用后,你可以通过访问以下URL来测试线程池:
http://localhost:8080/execute?taskName=test
总结
通过上述步骤,你可以在Spring Boot应用中创建和使用线程池,并将其配置成由Spring管理。这样可以方便地管理并发任务,提高应用的性能和响应能力。
Future介绍
Future
是 Java 中用于表示异步计算结果的接口。它的主要功能是允许你在任务还未完成时获取结果,而不是阻塞等待任务完成。Future
提供了一些方法来检查任务是否完成、等待任务完成并获取结果,以及取消任务等。
Future
接口的主要方法
Future
接口在 java.util.concurrent
包中定义,包含以下主要方法:
boolean cancel(boolean mayInterruptIfRunning)
:尝试取消任务。如果任务已经完成或已经被取消,则返回false
;如果任务成功取消,则返回true
。boolean isCancelled()
:如果任务在完成前被取消,则返回true
。boolean isDone()
:如果任务已完成,则返回true
。V get()
:等待任务完成并获取结果,如果任务未完成,则阻塞直到任务完成。V get(long timeout, TimeUnit unit)
:等待任务完成并获取结果,但只等待指定的时间。如果在超时时间内任务未完成,则抛出TimeoutException
。
示例代码
public class FutureTest {
public static void main(String[] args) {
// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(2);
// 提交任务
Future<Integer> future = executor.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
// 模拟长时间任务
Thread.sleep(2000);
return 123456;
}
});
// 检查任务是否完成
if (!future.isDone()) {
System.out.println("Task is not completed ...");
}
// 获取任务结果
try {
Integer result = future.get(); // 这将阻塞直到任务完成
System.out.println("Task completed!! Result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// 关闭线程池
executor.shutdown();
}
}
CompletableFuture
CompletableFuture
是 Java 8 引入的一个更高级的类,它实现了 Future
接口,并提供了更多功能,如流式处理和组合多个异步任务。CompletableFuture
允许更灵活的方式来处理异步计算,支持非阻塞、回调、异常处理等。
CompletableFuture
示例
public class CompletableFutureTest {
public static void main(String[] args) {
// 创建一个CompletableFuture
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
// 模拟长时间任务
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 123321;
});
// 添加回调
future.thenAccept(result -> System.out.println("Task completed!! Result: " + result));
// 等待任务完成
try {
future.get(); // 阻塞等待
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
- runAsync 适用于没有返回值的任务,返回 CompletableFuture。
CompletableFuture.runAsync(()->function());
- supplyAsync 适用于有返回值的任务,返回 CompletableFuture,其中 T 是任务返回的结果类型。
总结
Future
接口用于表示异步计算的结果,可以检查任务是否完成、获取结果或取消任务。CompletableFuture
是Future
的扩展,提供了更丰富的功能,如流式处理、组合多个异步任务、处理异常等。它更适合于现在Java应用中处理异步任务。
❤觉得有用的可以留个关注~~❤