ChenZhen 搜索
首页 标签 归档 留言板 友链 ChatGPT 提示库 AI工具导航网 🚇开往 关于我

多线程最佳实践

# 异步线程阻塞等待完成 当你遇到一个场景,需要同时启动多个任务,并等待所有任务完成后执行后续操作。这个方法很有用,比如你需要执行三个下载任务,当三个任务都下载完成后你才通知界面说完成,这个时候如果一个个去下载肯定耗时非常高,我们可以同时起三个线程去并行执行任务,减少总的执行时间。 下面是一段例子代码:

ChenZhen 2024-06-25T16:30:19

多线程最佳实践

实践一、异步线程阻塞等待完成

1. 两个异步线程执行完后阻塞

这种情况适合用在需要两个线程完成某个共同的任务,才能继续后续操作的场景。比如说,你在处理一个文件上传的功能,假设一个线程负责上传文件,另一个线程负责上传图片。只有在文件上传和图片上传都成功后,才能开始处理这个文件。

这时候,就需要这两个线程相互等待,确保一切都准备好了再进行下一步。这样可以避免出现文件未上传就提交订单的情况。

		// 创建第一个异步任务
        CompletableFuture<String> future1 = CompletableFuture.runAsync(() -> {
            try {
                System.out.println("Task 1 is running");
                Thread.sleep(2000); // 模拟任务执行
                return "Task 1 is completed";
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 创建第二个异步任务
        CompletableFuture<String> future2 = CompletableFuture.runAsync(() -> {
            try {
                System.out.println("Task 2 is running");
                Thread.sleep(3000); // 模拟任务执行
                return "Task 2 is completed";
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 创建一个CompletableFuture,等待两个异步任务都完成
        CompletableFuture<Void> allOf = CompletableFuture.allOf(future1, future2);
		allTasks.thenRun(() -> {
             try {
                 // 获取任务结果
                 String result1 = future1.get();
                 String result2 = future2.get();
                // 在此进行后续操作
                    
             } catch (Exception e) {
                 log.error("任务执行异常", e);
             }
		}).join();

2. 多个异步线程执行完后阻塞

当你遇到一个场景,需要同时启动多个任务,并等待所有任务完成后执行后续操作。这个方法很有用,比如你需要执行三个下载任务,当三个任务都下载完成后你才通知界面说完成,这个时候如果一个个去下载肯定耗时非常高,我们可以同时起三个线程去并行执行任务,减少总的执行时间。

下面是一段例子代码:

// 模拟N个下载任务列表
ArrayList<Object> downloadTaskList = new ArrayList<>();

List<CompletableFuture<Void>> futureList = downloadTaskList.stream().map(downloadParam -> CompletableFuture.runAsync(() -> {
    // 下载任务
    downloadTask(downloadParam);
})).collect(Collectors.toList());
// 等待所有异步任务完成
CompletableFuture<Void> allOf = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0]));
// 阻塞等待所有结果
allOf.join();
//执行其他操作

实践二、线程池统一管理方案

有时我们写代码时会遇到这样的提示,例如下面的代码,每次暴露服务都会创建一个新的线程池,并且业务结束之后线程池也未随之销毁。

类似这样频繁的创建、销毁线程和线程池,会给系统带来额外的开销。未经池化及统一管理的线程,则会导致系统内线程数上限不可控。

这种情况下,随着访问数增加,系统内线程数持续增长,CPU负载逐步提高。极端情况下,甚至可能会导致CPU资源被吃满,整个服务不可用。

为了解决上述问题,可增加统一线程池配置,替换掉自建线程和线程池。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author ChenZhen
 * @Description 自定义线程池
 * @create 2022/9/28 18:31
 * @QQ 1583296383
 * @WeXin(WeChat) ShockChen7
 */
@Configuration
@EnableAsync
public class AsyncPoolConfig {

    @Bean(name = "myExecutor")
    public ThreadPoolTaskExecutor asyncThreadPoolTaskExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(200);
        executor.setQueueCapacity(2000);
        executor.setKeepAliveSeconds(200);
        executor.setThreadNamePrefix("asyncThread");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);

        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        return executor;
    }

}

© 版权声明
😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘😗😚😙😋😛😜🤪😝🤑🤗🤭🤫🤔🤐🤨😐😑😶😏😒🙄😬🤥😌😔😪🤤😴😷🤒🤕🤢🤮🤧🥵🥶🥴😵🤯🤠🥳😎🤓🧐😕😟🙁☹️😮😯😲😳🥺😦😧😨😰😥😢😭😱😖😣😞😓😩😫🥱😤😡😠🤬