在Spring Boot中,可以通过使用@Async注解和ThreadPoolTaskExecutor线程池来实现异步调用自定义方法。 具体步骤如下:

1.在Spring Boot启动类上添加@EnableAsync注解来开启异步任务的支持:

@SpringBootApplication
@EnableAsync
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

2.在需要调用自定义方法的方法上使用@Async注解来表明这是一个异步方法:

@Service
public class UserService {
    @Async("myTaskExecutor")
    public void doSomeAsyncTask() {
        // 在这里编写需要异步执行的代码
    }
}

3.在配置类中定义一个ThreadPoolTaskExecutor线程池,并在@Bean注解上指定执行结束后的回调方法名:

@Configuration
public class ThreadConfig {

    @Bean("myTaskExecutor")
    public ThreadPoolTaskExecutor myTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(1000);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setThreadNamePrefix("myTaskExecutor-");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        executor.setTaskDecorator(new ContextDecorator());
        executor.setBeanName("myTaskExecutorBeanName");
        executor.initialize();

        executor.setTaskDecorator(new ContextDecorator());
        executor.setThreadNamePrefix("async-task-executor-");
        executor.initialize();

        executor.setTaskDecorator((runnable) -> {
           // 在任务执行结束后调用回调方法
           return () -> {
              try {
                  runnable.run();
              } finally {
                  System.out.println("任务执行结束,调用自定义回调方法");
              }
           };
        });

        return executor;
    }

    /**
     * 定义任务执行结束后的回调方法
     */
    public void taskCompleteCallback(Runnable runnable, Throwable throwable) {
        if (throwable == null) {
            // 执行成功
            System.out.println("任务执行成功");
        } else {
            // 执行失败
            System.out.println("任务执行失败");
        }
    }
}

在上面这个配置方法中,我们定义了一个ThreadPoolTaskExecutor线程池,并在@Bean注解上指定了线程池的名称。然后,在setTaskDecorator方法中,我们为线程池的任务添加了一个装饰器,用来在任务执行结束后调用回调方法。

最后,我们只需要在配置类中定义一个名为taskCompleteCallback的方法,该方法的参数必须是Runnable和Throwable类型,用来接收执行结束后的回调信息。

线程从ThreadLocal获取值时,会优先从自己的ThreadLocalMap中取值。如果当前线程没有设置该ThreadLocal,则会向上遍历当前线程的父线程,直到找到父线程的ThreadLocalMap中存储的值或者到达顶层线程。如果最终都没有找到,则返回ThreadLocal的初始值。

因此,每个线程之间的ThreadLocal是独立的,互不干扰,线程之间ThreadLocal的值互相不可见。

举个例子,假设有一个父线程P和一个子线程C。在父线程P中设置了一个ThreadLocal,并赋值为"value1"。然后,在子线程C中也设置了一个同名的ThreadLocal,并将其值设置为"value2"。当在子线程C中访问这个ThreadLocal时,会优先从子线程C的ThreadLocalMap中获取其值,即"value2"。如果子线程C中的ThreadLocalMap没有该值,则会向上遍历到父线程P的ThreadLocalMap中获取值,即"value1"。如果再向上遍历,最后会到达顶层线程中的ThreadLocalMap,如果仍然没有,则返回初始值。 在Java中,ThreadLocal的初始值是由initialValue()方法提供的。当从ThreadLocal获取值时,如果当前线程没有设置ThreadLocal的值,会调用initialValue()方法进行初始化,返回初始值,并存储到当前线程的ThreadLocalMap中。如果没有提供initialValue()方法,初始值为null。

举个例子,如果我们定义了一个ThreadLocal变量:

ThreadLocal<Integer> intThreadLocal = new ThreadLocal<Integer>() {
    @Override
    protected Integer initialValue() {
        return 0;
    }
};

这里通过重写ThreadLocal的initialValue()方法,将ThreadLocal的初始值设置为0。

当我们在某个线程中调用get()方法获取ThreadLocal的值时,如果该线程还没有设置过该ThreadLocal的值(即ThreadLocalMap中不存在该ThreadLocal的值),则会调用initialValue()方法,返回初始值0,并存储到该线程的ThreadLocalMap中。后续再次从该线程中获取该ThreadLocal的值时,就会直接从ThreadLocalMap中获取,而不会再调用initialValue()方法了。

ThreadLocal的get()方法会先从当前线程中的ThreadLocalMap中查找该ThreadLocal对象的值,如果当前线程没有设置该ThreadLocal的值,则会向上遍历当前线程的父线程,直到找到父线程的ThreadLocalMap中存储的值或者到达顶层线程。如果最终都没有找到,则会返回ThreadLocal的初始值。

具体来说,get()方法会先获取当前线程的ThreadLocalMap对象,并以该ThreadLocal对象为key查询ThreadLocalMap中是否存在相应的值。如果存在则直接返回,否则会尝试从父线程的ThreadLocalMap中查询,直到查询到顶级线程的ThreadLocalMap中仍然没有找到该ThreadLocal对象对应的值,此时会返回ThreadLocal的初始值。

需要注意的是,虽然ThreadLocal会从父线程中继承变量的值,但默认情况下,ThreadLocal的变量是不可见的,也就是说,每个线程有自己的ThreadLocalMap,线程之间是相互独立的。如果需要在父子线程之间共享ThreadLocal变量,需要使用共享ThreadLocal变量的工具类,如InheritableThreadLocal。

InheritableThreadLocal对象只是在子类get()的时候从父类复制已经的数据,之后子类再进行增删查操作时,只会影响当前线程对象,对于使用线程池的线程对象来说,重复使用线程对象时,该线程对象即使remove()之后,再get(),也无法继承父类了,因为该线程没有销毁,当前的ThreadLocalMap的key还存在!