开发者

SpringBoot异步线程父子线程数据传递的5种方式

开发者 https://www.devze.com 2024-08-10 14:41 出处:网络 作者: 242030
目录SpringBoot异步线程父子线程数据传递的5种方式1、ThreadLocal+TaskDecorator2、RequestContextHolder+TaskDecorator3、MDC+TaskDecorator4、InheritableThreadLocal5、TransmittableThreadLocal6、方案对比Sprin
目录
  • SpringBoot异步线程父子线程数据传递的5种方式
    • 1、ThreadLocal+TaskDecorator
    • 2、RequestContextHolder+TaskDecorator
    • 3、MDC+TaskDecorator
    • 4、InheritableThreadLocal
    • 5、TransmittableThreadLocal
    • 6、方案对比

SpringBoot异步线程父子线程数据传递的5种方式

1、ThreadLocal+TaskDecorator

package com.example.parentchildthreadspassingdata.threadLocal_taskDecorator;

/**
 * @author tom
 * 使用ThreadLocal存储共享的数据变量,如登录的用户信息
 */
public class UserUtils {

    private static final ThreadLocal<String> userLocal = new ThreadLocal<>();

    public static String getUserId() {
        return userLocal.get();
    }

    public static void setUserId(String userId) {
        userLocal.set(userId);
    }

    public static void clear() {
        userLocal.remove();
    }

}
package com.example.parentchildthreadspassingdata.threadLocal_taskDecorator;

import org.springframework.core.task.TaskDecorator;

/**
 * @author tom
 * 线程池修饰类
 */
public class CustomTaskDecorator implements TaskDecorator {

    @Override
    public Runnable decorate(Runnable runnable) {
        // 获取主线程中的请求信息(我们的用户信息也放在里面)
        String robotId = UserUtils.getUserId();
        return () -> {
            try {
                // 将主线程的请求信息,设置到子线程中
                UserUtils.setUserId(robotId);
                // 执行子线程,这一步不要忘了
                runnable.run();
            } finally {
                // 线程结束,清空这些信息,否则可能造成内存泄漏
                UserUtils.clear();
            }
        };
    }
}
package com.example.parentchildthreadspassingdata.threadLocal_taskDecorator;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;

import Java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author tom
 */
@Slf4j
public class VisibleThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {

    private void showThreadPoolInfo(String prefix) {
        ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();
        if (null == threadPoolExecutor) {
            return;
        }
        log.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]", this.getThreadNamePrefix(), prefix, threadPoolExecutor.getTaskCount(), threadPoolExecutor.getCompletedTaskCount(), threadPoolExecutor.getActiveCount(), threadPoolExecutor.getQueue().size());
    }

    @Override
    public void execute(Runnable task) {
        showThreadPoolInfo("1. do execute");
        super.execute(task);
    }

    @Override
    public void execute(Runnable task, long startTimeout) {
        showThreadPoolInfo("2. do execute");
        super.execute(task, startTimeout);
    }

    @Override
    public Future<?> submit(Runnable task) {
        showThreadPoolInfo("1. do submit");
        return super.submit(task);
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        showThreadPoolInfo("2. do submit");
        return super.submit(task);
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        showThreadPoolInfo("1. do submitListenable");
        return super.submitListenable(task);
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        showThreadPoolInfo("2. do submitListenable");
        return super.submitListenable(task);
    }
}
package com.example.parentchildthreadspassingdata.threadLocal_taskDecorator;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author tom
 */
@Slf4j
public class ExecutorConfig {

    @Bean(name = "asyncServiceExecutor1")
    public Executor asyncServiceExecutor() {
        log.info("start asyncServiceExecutor------------");
        // ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 使用可视化运行状态的线程池
        ThreadPoolTaskExecutor executor = new VisibleThreadPoolTaskExecutor();
        // 配置核心线程数
        executor.setCorePoolSize(2);
        // 配置最大线程数
        executor.setMaxPoolSize(2);
        // 配置队列大小
        executor.setQueueCapacity(60);
        // 配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("my-thread");
        // rejection-policy: 当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS: 不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 增加线程池修饰类
        executor.setTaskDecorator(new CustomTaskDecorator());
        // 执行初始化
        executor.initialize();
        log.info("end asyncServiceExecutor------------");
        return executor;
    }
}
package com.example.parentchildthreadspassingdata.threadLocal_taskDecorator;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;

/**
 * @author tom
 */
@Slf4j
@Service("asyncServiceImpl1")
public class AsyncServiceImpl {

    /**
     * 使用ThreadLocal方式传递
     * 带有返回值
     *
     * @throws InterruptedException
     */
    @Async("asyncServiceExecutor1")
    public CompletableFuture<String> executeValueAsync1() {
        log.info("start executeValueAsync");
        System.out.println("异步线程执行返回结果......");
        log.info("end executeValueAsync");
        return CompletableFuture.completedFuture(UserUtils.getUserId());
    }

}
package com.example.parentchildthreadspassingdata.threadLocal_taskDecorator;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * @author tom
 */
@Slf4j
@RestController
public class Test1Controller {

    private AsyncServiceImpl asyncService;

    @Autowired
    @Qualifier(value = "asyncServiceImpl1")
    public void setAsyncService(AsyncServiceImpl asyncService) {
        this.asyncService = asyncService;
    }

    /**
     * 使用ThreadLocal+TaskDecorator的方式
     *
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     */
    @GetMapping("/test1")
    public String test1() throws ExecutionException, InterruptedException {
        UserUtils.setUserId("123456");
        CompletableFuture<String> completableFuture = asyncService.executeValueAsync1();
        String s = completableFuture.get();
        log.info("result {}", s);
        return s;
    }
}

2、RequestContextHolder+TaskDecorator

package com.example.parentchildthreadspassingdata.requestcontextholder_taskdecorator;

import org.springframework.core.task.TaskDecorator;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

/**
 * @author tom
 * 线程池修饰类
 */
public class CustomTaskDecorator implements TaskDecorator {

    @Override
    public Runnable decorate(Runnable runnable) {
        // 获取主线程中的请求信息(我们的用户信息也放在里面)
        RequestAttributes attributes = RequestContexhttp://www.devze.comtHolder.getRequestAttributes();
        return () -> {
            try {
                // 将主线程的请求信息,设置到子线程中
                RequestContextHolder.setRequestAttributes(attributes);
                // 执行子线程,这一步不要忘了
                runnable.run();
            } finally {
                // 线程结束,清空这些信息,否则可能造成内存泄漏
                RequestContextHolder.resetRequestAttributes();
            }
        };
    }
}
package com.example.parentchildthreadspassingdata.requestcontextholder_taskdecorator;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;

import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author tom
 */
@Slf4j
public class VisibleThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {

    private void showThreadPoolInfo(String prefix) {
        ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();
        if (null == threadPoolExecutor) {
            return;
        }
        log.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]", this.getThreadNamePrefix(), prefix, threadPoolExecutor.getTaskCount(), threadPoolExecutor.getCompletedTaskCount(), threadPoolExecutor.getActiveCount(), threadPoolExecutor.getQueue().size());
    }

    @Override
    public void execute(Runnable task) {
        showThreadPoolInfo("1. do execute");
        super.execute(task);
    }

    @Override
    public void execute(Runnable task, long startTimeout) {
        showThreadPoolInfo("2. do execute");
        super.execute(task, startTimeout);
    }

    @Override
    public Future<?> submit(Runnable task) {
        showThreadPoolInfo("1. do submit");
        return super.submit(task);
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        showThreadPoolInfo("2. do submit");
        return super.submit(task);
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        showThreadPoolInfo("1. do submitListenable");
        return super.submitListenable(task);
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        showThreadPoolInfo("2. do submitListenable");
        return super.submitListenable(task);
    }
}
package com.example.parentchildthreadspassingdata.requestcontextholder_taskdecorator;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author tom
 */
@Slf4j
public class ExecutorConfig {

    @Bean(name = "asyncServiceExecutor2")
    public Executor asyncServiceExecutor() {
        log.info("start asyncServiceExecutor------------");
        // ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 使用可视化运行状态的线程池
        ThreadPoolTaskExecutor executor = new VisibleThreadPoolTaskExecutor();
        // 配置核心线程数
        executor.setCorePoolSize(2);
        // 配置最大线程数
        executor.setMaxPoolSize(2);
        // 配置队列大小
        executor.setQueueCapacity(60);
        // 配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("my-thread");
        // rejection-policy: 当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //增加线程池修饰类
        executor.setTaskDecorator(new CustomTaskDecorator());
        // 执行初始化
        executor.initialize();
        log.info("end asyncServiceExecutor------------");
        return executor;
    }
}
package com.example.parentchildthreadspassingdata.requestcontextholder_taskdecorator;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.util.concurrent.CompletableFuture;

/**
 * @author tom
 */
@Slf4j
@Service("asyncServiceImpl2")
public class AsyncServiceImpl {

    /**
     * 使用RequestAttributes获取主线程传递的数据
     *
     * @return
     * @throws InterruptedException
     */
    @Async("asyncServiceExecutor2")
    public CompletableFuture<String> executeValueAsync2(){
        log.info("start executeValueAsync");
        System.out.println("异步线程执行返回结果......");
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        Object userId = attributes.getAttribute("userId", 0);
        log.info("end executeValueAsync");
        return CompletableFuture.completedFuture(userId.toString());
    }

}
package com.example.parentchildthreadspassingdata.requestcontextholder_taskdecorator;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * @author tom
 */
@Slf4j
@RestController
public class Test2Controller {

    private AsyncServiceImpl asyncService;

    @Autowired
    @Qualifier(value = "asyncServiceImpl2")
    public void setAsyncService(AsyncServiceImpl asyncService) {
        this.asyncService = asyncService;
    }

    /**
     * RequestContextHolder+TaskDecorator的方式
     *
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     */
    @GetMapping("/test2")
    public String test2() throws InterruptedException, ExecutionException {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        attributes.setAttribute("userId", "123456", 0);
        CompletableFuture<String> completableFuture = asyncService.executeValueAsync2();
        String s = completableFuture.get();
        log.info("result {}", s);
        return s;
    }
}

3、MDC+TaskDecorator

package com.example.parentchildthreadspassingdata.mdc_taskdecorator;

import org.slf4j.MDC;
import org.springframework.core.task.TaskDecorator;

/**
 * @author tom
 * 线程池修饰类
 */
public class MdcTaskDecorator implements TaskDecorator {

    @Override
    public Runnable decorate(Runnable runnable) {
        // 获取主线程中的请求信息(我们的用户信息也放在里面)
        String userId = MDC.get("userId");
        return () -> {
            try {
                // 将主线程的请求信息,设置到子线程中
                MDC.put("userId", userId);
                // 执行子线程,这一步不要忘了
                runnable.run();
            } finally {
                // 线程结束,清空这些信息,否则可能造成内存泄漏
                MDC.clear();
            }
        };
    }
}
package com.example.parentchildthreadspassingdata.mdc_taskdecorator;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;

import java.util.concurjsrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author tom
 */
@Slf4j
public class VisibleThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {

    private void showThreadPoolInfo(String prefix) {
        ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();
        if (null == threadPoolExecutor) {
            return;
        }
        log.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]", this.getThreadNamePrefix(), prefix, threadPoolExecutor.getTaskCount(), threadPoolExecutor.getCompletedTaskCount(), threadPoolExecutor.getActiveCount(), threadPoolExecutor.getQueue().size());
    }

    @Override
    public void execute(Runnable task) {
        showThreadPoolInfo("1. do execute");
        super.execute(task);
    }

    @Override
    public void execute(Runnable task, long startTimeout) {
        showThreadPoolInfo("2. do execute");
        super.execute(task, startTimeout);
    }

    @Override
    public Future<?> submit(Runnable task) {
        showThreadPoolInfo("1. do submit");
        return super.submit(task);
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        showThreadPoolInfo("2. do submit");
        return super.submit(task);
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        showThreadPoolInfo("1. do submitListenable");
        return super.submitListenable(task);
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        showThreadPoolInfo("2. do submitListenable");
        return super.submitListenable(task);
    }
}
package com.example.parentchildthreadspassingdata.mdc_taskdecorator;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author tom
 */
@Slf4j
public class ExecutorConfig {

    @Bean(name = "asyncServiceExecutor3")
    public Executor asyncServiceExecutor() {
        log.info("start asyncServiceExecutor------------");
        // ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 使用可视化运行状态的线程池
        ThreadPoolTaskExecutor executor = new VisibleThreadPoolTaskExecutor();
        // 配置核心线程数
        executor.setCorePoolSize(2);
        // 配置最大线程数
        executor.setMaxPoolSize(2);
        // 配置队列大小
        executor.setQueueCapacity(60);
        // 配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("my-thread");
        // rejection-policy: 当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS: 不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //增加MDC的线程池修饰类
        executor.setTaskDecorator(new MdcTaskDecorator());
        //执行初始化
        executor.initialize();
        log.info("end asyncServiceExecutor------------");
        return executor;
    }
}
package com.example.parentchildthreadspassingdata.mdc_taskdecorator;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;

/**
 * @author tom
 */
@Slf4j
@Service("asyncServiceImpl3")
public class AsyncServiceImpl {

    /**
     * 使用MDC获取主线程传递的数据
     *
     * @return
     * @throws InterruptedException
     */
    @Async("asyncServiceExecutor3")
    public CompletableFuture<String> executeValueAsync3() {
        log.info("start executeValueAsync");
        System.out.println("异步线程执行返回结果......");
        log.info("end executeValueAsync");
        return CompletableFuture.completedFuture(MDC.get("userId"));
    }
}
package com.example.parentchildthreadspassingdata.mdc_taskdecorator;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * @author tom
 */
@Slf4j
@RestController
public class Test3Controller {

    private AsyncServiceImpl asyncService;

    @Autowired
    @Qualifier(value = "asyncServiceImpl3")
    public void setAsyncService(AsyncServiceImpl asyncService) {
        this.asyncService = asyncService;
    }

    /**
     * 使用MDC+TaskDecorator方式
     * 本质也是ThreadLocal+TaskDecorator方式
     *
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     */
    @GetMapping("/test3")
    public String test3() throws InterruptedException, ExecutionException {
        MDC.put("userId", "123456");
        CompletableFuture<String> completableFuture = asyncService.executeValueAsync3();
        String s = completableFuture.get();
        log.info("result {}", s);
        return s;
    }
}

4、InheritableThreadLocal

package com.example.parentchildthreadspassingdata.inheritablethreadlocal;

/**
 * @author tom
 * 使用InheritableThreadLocal存储线程之间共享的数据变量,如登录的用户信息
 */
public class UserInheritableUtils {

    private static final InheritableThreadLocal<String> userLocal = new InheritableThreadLocal<>();

    public static String getUserId() {
        return userLocal.get();
    }

    public static void setUserId(String userId) {
        userLocal.set(userId);
    }

    public static void clear() {
        userLocal.remove();
    }

}
package com.example.parentchildthreadspassingdata.inheritablethreadlocal;

import com.example.pKoxgSarentchildthreadspassingdata.mdc_taskdecorator.VisibleThreadPoolTaskExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author tom
 */
@Slf4j
public class ExecutorConfig {

    @Bean(name = "asyncServiceExecutor4")
    public Executor asyncServiceExecutor() {
        log.info("start asyncServiceExecutor------------");
        // ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 使用可视化运行状态的线程池
        ThreadPoolTaskExecutor executor = new VisibleThreadPoolTaskExecutor();
        // 配置核心线程数
        executor.setCorePoolSize(2);
        // 配置最大线程数
        executor.setMaxPoolSize(2);
        // 配置队列大小
        executor.setQueueCapacity(60);
        // 配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("my-thread");
        // rejection-policy: 当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS: 不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        log.info("end asyncServiceExecutor------------");
        return executor;
    }
}
package com.example.parentchildthreadspassingdata.inheritablethreadlocal;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;

/**
 * @author
 */
@Slf4j
@Service("asyncServiceImpl4")
public class AsyncServiceImpl {

    /**
     * 使用InheritableThreadLocal获取主线程传递的数据
     *
     * @return
     * @throws InterruptedException
     */
    @Async("asyncServiceExecutor4")
    public CompletableFuture<String> executeValueAsync4() {
        log.info("start executeValueAsync");
       php System.out.println("异步线程执行返回结果......");
        log.info("end executeValueAsync");
        return CompletableFuture.completedFuture(UserInheritableUtils.getUserId());
    }
}
package com.example.parentchildthreadspassingdata.inheritablethreadlocal;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * @author tom
 */
@Slf4j
@RestController
public class Test4Controller {

    private AsyncServiceImpl asyncService;

    @Autowired
    @Qualifier(value = "asyncServiceImpl4")
    public void setAsyncService(AsyncServiceImpl asyncService) {
        this.asyncService = asyncService;
    }

    /**
     * 使用InheritableThreadLocal方式
     *
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     */
    @GetMapping("/test4")
    public String test4() throws InterruptedException, ExecutionException {
        UserInheritableUtils.setUserId("123456");
        CompletableFuture<String> completableFuture = asyncService.executeValueAsync4();
        String s = completableFuture.get();
        log.info("result {}", s);
        return s;
    }
}

5、TransmittableThreadLocal

package com.example.parentchildthreadspassingdata.transmittablethreadlocal;

import com.alibaba.ttl.TransmittableThreadLocal;

/**
 * @author tom
 * 使用TransmittableThreadLocal存储线程之间共享的数据变量,如登录的用户信息
 */
public class UserTransmittableUtils {

    private static final TransmittableThreadLocal<String> userLocal = new TransmittableThreadLocal<>();

    public static String getUserId() {
        return userLocal.get();
    }

    public static void setUserId(String userId) {
        userLocal.set(userId);
    }

    public static void clear() {
        userLocal.remove();
    }
}
package com.example.parentchildthreadspassingdata.transmittablethreadlocal;

import com.example.parentchildthreadspassingdata.mdc_taskdecorator.VisibleThreadPoolTaskExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author tom
 */
@Slf4j
public class ExecutorConfig {

    @Bean(name = "asyncServiceExecutor5")
    public Executor asyncServiceExecutor() {
        log.info("start asyncServiceExecutor------------");
        // ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 使用可视化运行状态的线程池
        ThreadPoolTaskExecutor executor = new VisibleThreadPoolTaskExecutor();
        // 配置核心线程数
        executor.setCorePoolSize(2);
        // 配置最大线程数
        executor.setMaxPoolSize(2);
        // 配置队列大小
        executor.setQueueCapacity(60);
        // 配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("my-thread");
        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS: 不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 执行初始化
        executor.initialize();
        log.info("end asyncServiceExecutor------------");
        return executor;
    }
}
package com.example.parentchildthreadspassingdata.transmittablethreadlocal;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;

/**
 * @author tom
 */
@Slf4j
@Service("asyncServiceImpl5")
public class AsyncServiceImpl {

    /**
     * 使用TransmittableThreadLocal获取主线程传递的数据
     *
     * @return
     * @throws InterruptedException
     */
    @Async("asyncServiceExecutor5")
    public CompletableFuture<String> executeValueAsync5() {
        log.info("start executeValueAsync");
        System.out.println("异步线程执行返回结果......");
        log.info("end executeValueAsync");
        return CompletableFuture.completedFuture(UserTransmittableUtils.getUserId());
    }
}
package com.example.parentchildthreadspassingdata.transmittablethreadlocal;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * @author tom
 */
@RestController
@Slf4j
public class Test5Controller {

    private AsyncServiceImpl asKoxgSyncService;

    @Autowired
    @Qualifier(value = "asyncServiceImpl5")
    public void setAsyncService(AsyncServiceImpl asyncService) {
        this.asyncService = asyncService;
    }

    /**
     * 使用TransmittableThreadLocal方式
     *
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     */
    @GetMapping("/test5")
    public String test5() throws InterruptedException, ExecutionException {
        UserTransmittableUtils.setUserId("123456");
        CompletableFuture<String> completableFuture = asyncService.executeValueAsync5();
        String s = completableFuture.get();
        log.info("result {}", s);
        return s;
    }
}

6、方案对比

方案1,方案2,方案3主要是借助 TaskDecorator 进行父子线程之间传递数据。其中 MDC 方案主要借鉴于 MDC

的日志跟踪的思想来实现。

方案4和方案5使用 InheritableThreadLocal 和 TransmittableThreadLocal 来实现,其中

TransmittableThreadLocal 是阿里 InheritableThreadLocal 进行优化封装。

本人推荐使用方案5。

以上就是SpringBoot异步线程父子线程数据传递的5种方式的详细内容,更多关于SpringBoot父子线程数据传递的资料请关注编程客栈(www.devze.com)其它相关文章!

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号