欢迎光临散文网 会员登陆 & 注册

Spring框架中的线程池

2023-06-16 09:33 作者:chaojilaji123  | 我要投稿

原文合集地址如下,有需要的朋友可以关注


[本文地址](https://mp.weixin.qq.com/s/FCeSlVNImbxKU6Be_YJA1A)


[合集地址](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzI5MjY4OTQ2Nw==&action=getalbum&album_id=2970034039967449094&scene=173&from_msgid=2247484208&from_itemidx=1&count=3&nolastread=1#wechat_redirect)


# Spring框架中的线程池

## 使用Java的ExecutorService接口实现

`ExecutorService`是Java提供的用于管理线程池的高级工具。


下面是在Spring框架中使用线程池的一般步骤:


### 导入所需的依赖

首先,确保你的项目中包含了使用线程池所需的依赖。通常情况下,你可以使用Spring Boot来创建项目,它会自动包含线程池相关的依赖。


### 创建线程池

在Spring中,你可以通过配置文件或使用Java代码来创建线程池。如果你使用配置文件,可以在`application.properties`或`application.yml`文件中配置线程池的属性。如果你使用Java代码,可以通过创建`ThreadPoolTaskExecutor`或`ThreadPoolExecutor`对象来实现。


   ```java

   // 通过Java代码创建线程池

   @Bean

   public ExecutorService taskExecutor() {

       ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

       executor.setCorePoolSize(10); // 设置核心线程数

       executor.setMaxPoolSize(20); // 设置最大线程数

       executor.setQueueCapacity(30); // 设置队列容量

       executor.setThreadNamePrefix("MyThread-"); // 设置线程名前缀

       executor.initialize();

       return executor;

   }

   ```


### 在需要使用线程池的地方注入它

在你的代码中,如果你需要使用线程池来执行异步任务或并发处理,你可以通过在需要使用的地方注入线程池来实现。


   ```java

   @Autowired

   private ExecutorService taskExecutor;

   ```


### 提交任务给线程池

一旦你注入了线程池,你就可以使用它来提交任务。


   ```java

   taskExecutor.execute(() -> {

       // 在这里编写你的任务逻辑

   });

   ```


   或者,如果你需要获取任务的结果,你可以使用`submit()`方法。


   ```java

   Future<Result> future = taskExecutor.submit(() -> {

       // 在这里编写你的任务逻辑,并返回一个结果

       return result;

   });

   ```


### 销毁线程池

在Spring应用程序关闭时,确保销毁线程池以释放资源。


   ```java

   @PreDestroy

   public void shutdown() {

       if (taskExecutor instanceof ExecutorService) {

           ((ExecutorService) taskExecutor).shutdown();

       }

   }

   ```


以上是在Spring框架中使用线程池的基本步骤。你可以根据自己的需求和具体的场景来配置线程池的属性和使用方式。


## 使用@Async注解使用异步线程池执行任务

在Spring框架中,使用`@Async`注解可以将方法标记为异步执行的方法,使其在调用时会被自动提交到线程池中执行,而不会阻塞主线程。


以下是使用`@Async`注解的步骤:


### 导入所需的依赖

确保你的项目中包含了使用`@Async`注解所需的依赖。通常情况下,你可以使用Spring Boot来创建项目,它会自动包含相关的依赖。


### 启用异步支持

在Spring配置中,你需要启用异步支持。如果你使用Java配置方式,可以在配置类上加上`@EnableAsync`注解。如果你使用XML配置方式,可以在XML配置文件中添加`<task:annotation-driven executor="taskExecutor" />`。


### 在需要异步执行的方法上添加`@Async`注解

将`@Async`注解添加到你希望异步执行的方法上。


   ```java

   @Async

   public void asyncMethod() {

       // 异步执行的方法逻辑

   }

   ```


### 配置线程池并指定任务执行器名称(可选)

Spring框架默认使用`SimpleAsyncTaskExecutor`作为任务执行器,但你也可以自定义线程池并指定任务执行器的名称。在配置类中创建一个`TaskExecutor`的bean,并通过`@Async`注解的`value`属性或`Executor`参数指定任务执行器的名称。


   ```java

   @Bean("taskExecutor")

   public Executor taskExecutor() {

       ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

       executor.setCorePoolSize(10);

       executor.setMaxPoolSize(20);

       executor.setQueueCapacity(30);

       executor.setThreadNamePrefix("MyThread-");

       executor.initialize();

       return executor;

   }


   // 使用@Async注解并指定任务执行器名称

   @Async("taskExecutor")

   public void asyncMethodWithCustomExecutor() {

       // 异步执行的方法逻辑

   }

   ```


#### 关于SimpleAsyncTaskExecutor

`SimpleAsyncTaskExecutor`是Spring框架提供的默认的任务执行器,它是基于Java的`Executor`接口实现的简单的线程池。


要配置`SimpleAsyncTaskExecutor`,你可以在Spring的配置类中创建一个`TaskExecutor`的bean,并将其返回。以下是一个示例:


```java

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.core.task.SimpleAsyncTaskExecutor;

import org.springframework.core.task.TaskExecutor;


@Configuration

public class AppConfig {


    @Bean

    public TaskExecutor taskExecutor() {

        SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();

        executor.setConcurrencyLimit(10); // 设置并发限制,默认为无限制

        executor.setThreadNamePrefix("MyThread-"); // 设置线程名前缀

        return executor;

    }


}

```


在上述示例中,我们创建了一个`TaskExecutor`的bean,并将其返回。`SimpleAsyncTaskExecutor`的实例被创建,并通过`setConcurrencyLimit()`方法设置了并发限制,这是可选的,默认为无限制。`setThreadNamePrefix()`方法设置了线程名的前缀,以便于识别任务执行的线程。


你可以根据需要进行其他配置,`SimpleAsyncTaskExecutor`还提供了其他方法,例如`setThreadGroupName()`、`setDaemon()`等,可以根据具体需求进行设置。


在使用`SimpleAsyncTaskExecutor`时,它会根据需要创建新的线程来执行任务,不会重用线程。因此,它适用于短期、简单的异步任务,但对于长期运行的任务或需要复杂线程池配置的场景,可能需要使用其他实现,如`ThreadPoolTaskExecutor`。


请注意,`SimpleAsyncTaskExecutor`不适合高负载的应用程序,因为它没有线程池的管理机制,并且没有对队列容量、拒绝策略等进行配置。如果你的应用程序需要更高级的线程池管理功能,建议使用`ThreadPoolTaskExecutor`或其他支持更多配置选项的任务执行器。


### 关于ThreadPoolTaskExecutor

`ThreadPoolTaskExecutor`是Spring框架提供的一个基于Java的`ThreadPoolExecutor`的封装,它提供了更多的线程池管理功能和配置选项。


要配置`ThreadPoolTaskExecutor`,你可以在Spring的配置类中创建一个`TaskExecutor`的bean,并进行相应的配置。以下是一个示例:


```java

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import org.springframework.core.task.TaskExecutor;


@Configuration

public class AppConfig {


    @Bean

    public TaskExecutor taskExecutor() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        executor.setCorePoolSize(10); // 设置核心线程数

        executor.setMaxPoolSize(20); // 设置最大线程数

        executor.setQueueCapacity(30); // 设置队列容量

        executor.setThreadNamePrefix("MyThread-"); // 设置线程名前缀

        executor.initialize();

        return executor;

    }


}

```


在上述示例中,我们创建了一个`TaskExecutor`的bean,并将其返回。`ThreadPoolTaskExecutor`的实例被创建,并通过一系列的`set`方法进行配置,包括:


- `setCorePoolSize(int corePoolSize)`: 设置核心线程数,即线程池中保持的线程数量。

- `setMaxPoolSize(int maxPoolSize)`: 设置最大线程数,即线程池允许的最大线程数量。

- `setQueueCapacity(int queueCapacity)`: 设置队列容量,即线程池任务队列的最大容量。

- `setThreadNamePrefix(String threadNamePrefix)`: 设置线程名的前缀,以便于识别任务执行的线程。

- `initialize()`: 初始化线程池。


除了上述方法,`ThreadPoolTaskExecutor`还提供了其他配置选项,如`setKeepAliveSeconds()`、`setAllowCoreThreadTimeOut()`、`setRejectedExecutionHandler()`等,可以根据具体需求进行设置。


配置完成后,你可以将`ThreadPoolTaskExecutor`用作任务执行器,通过在`@Async`注解中指定任务执行器的名称或通过注入使用它。


请注意,`ThreadPoolTaskExecutor`提供了线程池的管理功能,可以根据任务的情况自动调整线程池的大小,对于长期运行的异步任务或需要更高级的线程池管理的场景,它是更常用的选择。


### 调用异步方法

在其他组件或类中,直接调用带有`@Async`注解的异步方法即可。


   ```java

   myService.asyncMethod();

   ```


`@Async`注解可以在后面加入一个名字,用于指定具体的任务执行器,如上面的示例中的`@Async("taskExecutor")`。这样做的好处是,你可以针对不同的异步任务使用不同的线程池或任务执行器。


注意事项:

- 异步方法必须定义在Spring管理的Bean中,因为Spring会通过代理来拦截方法调用并将其提交给线程池。

- 使用`@Async`注解时,如果异步方法内部发生了异常,调用者不会收到异常,因为异步方法在独立的线程中执行。若需要捕获异常,可以使用`Future`来获取异步任务的执行结果并处理异常。

- 确保在Spring的配置中启用了异步支持,否则`@Async`注解将不起作用。


这些是使用`@Async`注解实现异步方法的基本步骤,可以根据具体需求进行配置和使用。



## @Async的实现原理

@Async注解的实现原理使用了AOP、动态代理、Java反射、线程池、Runnable和Callable接口、Future接口、Java并发类库等技术和类库,通过这些技术和类库的组合,实现了异步方法的调用和执行。


### 异步方法的代理生成

当Spring扫描到带有@Async注解的方法时,它会生成一个代理对象来封装该方法。


以下是Spring框架中生成代理对象的代码示例:


```java

public class AsyncAnnotationBeanPostProcessor implements BeanPostProcessor, Ordered {


    // ...


    @Override

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        Class<?> targetClass = AopUtils.getTargetClass(bean);

        for (Method method : targetClass.getMethods()) {

            Async asyncAnnotation = AnnotationUtils.findAnnotation(method, Async.class);

            if (asyncAnnotation != null) {

                // 创建代理对象

                Object proxy = createAsyncProxy(bean, beanName, method);

                return proxy;

            }

        }

        return bean;

    }


    private Object createAsyncProxy(Object bean, String beanName, Method method) {

        ProxyFactory proxyFactory = new ProxyFactory();

        proxyFactory.setTarget(bean);

        proxyFactory.addAdvisor(asyncAdvisor);

        proxyFactory.setFrozen(true);

        proxyFactory.setProxyTargetClass(true);

        return proxyFactory.getProxy();

    }


    // ...


}

```


在上述代码中,`AsyncAnnotationBeanPostProcessor`实现了`BeanPostProcessor`接口,用于在Bean初始化之前对带有`@Async`注解的方法进行处理。当Spring扫描到带有`@Async`注解的方法时,`postProcessBeforeInitialization()`方法会被调用。


在`postProcessBeforeInitialization()`方法中,首先通过`AopUtils.getTargetClass(bean)`获取目标类的类型,然后遍历目标类的所有方法。对于每个方法,使用`AnnotationUtils.findAnnotation(method, Async.class)`查找是否有`@Async`注解。


如果找到了带有`@Async`注解的方法,就会调用`createAsyncProxy()`方法创建代理对象。在`createAsyncProxy()`方法中,通过`ProxyFactory`创建一个代理工厂,并设置目标对象、添加`asyncAdvisor`(异步处理的通知器),以及其他配置。最后调用`proxyFactory.getProxy()`获取代理对象,并将其返回。


通过以上代码,Spring框架在扫描到带有`@Async`注解的方法时,会生成一个代理对象来封装该方法,实现异步调用的功能。这样,在调用带有`@Async`注解的方法时,实际上是通过代理对象来调用的,从而实现了异步执行。


### 任务执行器的选择

根据@Async注解的配置,Spring会根据指定的任务执行器名称选择相应的任务执行器。如果没有指定名称,它将使用默认的任务执行器。


在Spring中,根据`@Async`注解的配置选择任务执行器的过程涉及以下几个关键的源码部分:


#### `AsyncAnnotationBeanPostProcessor`类

该类是一个`BeanPostProcessor`,用于处理带有`@Async`注解的方法。在方法`postProcessBeforeInitialization()`中,它会检查方法上的`@Async`注解的配置,并根据配置选择任务执行器。


#### `AsyncConfigurer`接口

该接口定义了配置任务执行器的方法。你可以通过实现该接口来自定义任务执行器的配置。其中,`getAsyncExecutor()`方法用于返回一个`Executor`对象,即任务执行器。


#### `AnnotationAsyncExecutionInterceptor`类

该类是一个AOP的`MethodInterceptor`,用于在调用带有`@Async`注解的方法时进行拦截。在`invoke()`方法中,它会检查方法上的`@Async`注解的配置,并从`AsyncAnnotationInterceptor`中获取任务执行器。


#### `AsyncAnnotationInterceptor`类

该类是一个AOP的`MethodInterceptor`,用于处理带有`@Async`注解的方法。在`invoke()`方法中,它会获取任务执行器,并使用任务执行器来执行异步任务。


#### 相关的源码示例


```java

public class AsyncAnnotationBeanPostProcessor implements BeanPostProcessor, Ordered {


    private AsyncConfigurer asyncConfigurer;


    @Override

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        // ...


        // 根据@Async注解的配置获取任务执行器

        Executor executor = getExecutor(asyncAnnotation);


        // ...


        // 创建代理对象并设置任务执行器

        Object proxy = createAsyncProxy(bean, beanName, method, executor);


        // ...

    }


    private Executor getExecutor(Async asyncAnnotation) {

        // 从AsyncConfigurer中获取任务执行器

        Executor executor = this.asyncConfigurer.getAsyncExecutor();

        if (executor == null && this.asyncConfigurer instanceof ApplicationContextAware) {

            executor = ((ApplicationContextAware) this.asyncConfigurer).getApplicationContext()

                    .getBean(TaskExecutor.class);

        }

        if (executor == null) {

            throw new IllegalStateException("No executor specified for async annotation processing");

        }

        return executor;

    }


    // ...


    private Object createAsyncProxy(Object bean, String beanName, Method method, Executor executor) {

        ProxyFactory proxyFactory = new ProxyFactory();

        proxyFactory.setTarget(bean);

        proxyFactory.addAdvisor(asyncAdvisor);


        // 设置任务执行器

        proxyFactory.addAdvice(new AnnotationAsyncExecutionInterceptor(executor));


        proxyFactory.setFrozen(true);

        proxyFactory.setProxyTargetClass(true);

        return proxyFactory.getProxy();

    }


    // ...

}


public class AnnotationAsyncExecutionInterceptor implements MethodInterceptor {


    private final Executor executor;


    public AnnotationAsyncExecutionInterceptor(Executor executor) {

        this.executor = executor;

    }


    @Override

    public Object invoke(MethodInvocation invocation) throws Throwable {

        // 获取目标方法上的@Async注解的配置信息


        // ...


        // 执行异步任务

        Future<?> future = executor.submit(task);


        // ...

    }


    // ...

}

```


在上述代码中,`AsyncAnnotationBeanPostProcessor`类通过`getExecutor()`方法获取任务执行器,该方法会优先从`AsyncConfigurer`中获取执行


器,如果未配置,则从Spring容器中获取`TaskExecutor` bean。然后,在创建代理对象时,将任务执行器传递给`AnnotationAsyncExecutionInterceptor`。


`AnnotationAsyncExecutionInterceptor`类的`invoke()`方法中,使用获取到的任务执行器来执行异步任务,通过`executor.submit(task)`将任务提交给执行器。


通过上述源码,当Spring扫描到带有`@Async`注解的方法时,会根据配置获取任务执行器,并将其传递给代理对象,在执行异步方法时使用相应的任务执行器。这样就可以根据配置选择不同的任务执行器来处理异步方法的调用。


### 方法调用的封装

代理对象在调用异步方法时,会将该方法的执行请求封装成一个Runnable或Callable的任务,并提交给任务执行器。任务执行器会负责管理线程池,并在合适的时间执行异步任务。


在Spring中,代理对象在调用异步方法时,会将该方法的执行请求封装成一个`Runnable`或`Callable`的任务,并提交给任务执行器。这个过程涉及以下关键的源码部分:


#### `AnnotationAsyncExecutionInterceptor`类

该类是一个AOP的`MethodInterceptor`,用于处理带有`@Async`注解的方法。在`invoke()`方法中,它会将异步方法的执行请求封装成`Runnable`或`Callable`的任务对象。


#### `AsyncExecutionInterceptor.AsyncExecutionRunnable`类和`AsyncExecutionInterceptor.AsyncExecutionCallable`类

这两个类分别实现了`Runnable`和`Callable`接口,用于封装异步方法的执行逻辑。


#### `TaskExecutor`接口和其实现类

Spring提供了多个实现了`TaskExecutor`接口的任务执行器,例如`ThreadPoolTaskExecutor`、`SimpleAsyncTaskExecutor`等。任务执行器负责管理线程池,并执行提交的任务。


#### 相关源码示例


```java

public class AnnotationAsyncExecutionInterceptor implements MethodInterceptor {


    private final Executor executor;


    public AnnotationAsyncExecutionInterceptor(Executor executor) {

        this.executor = executor;

    }


    @Override

    public Object invoke(MethodInvocation invocation) throws Throwable {

        // 获取目标方法上的@Async注解的配置信息


        // ...


        // 封装异步任务

        Runnable task = new AsyncExecutionRunnable(executor, asyncAnnotation, invocation);


        // 提交异步任务给任务执行器

        executor.execute(task);


        // 如果有返回值,则返回Future对象

        if (hasReturnType) {

            // 创建并返回Future对象

            return createFutureResult(asyncAnnotation, task);

        } else {

            return null;

        }

    }


    // ...

}


public class AsyncExecutionRunnable implements Runnable {


    private final Executor executor;

    private final Async asyncAnnotation;

    private final MethodInvocation invocation;


    public AsyncExecutionRunnable(Executor executor, Async asyncAnnotation, MethodInvocation invocation) {

        this.executor = executor;

        this.asyncAnnotation = asyncAnnotation;

        this.invocation = invocation;

    }


    @Override

    public void run() {

        try {

            // 执行异步方法

            invocation.proceed();

        } catch (Throwable ex) {

            // 处理异常

        }

    }

}


public interface TaskExecutor {


    void execute(Runnable task);


    // ...

}


public class ThreadPoolTaskExecutor implements TaskExecutor {


    // ...


    @Override

    public void execute(Runnable task) {

        // 提交任务给线程池执行

        getThreadPoolExecutor().execute(task);

    }


    // ...

}

```


在上述代码中,`AnnotationAsyncExecutionInterceptor`类的`invoke()`方法中,首先根据`@Async`注解的配置信息,创建一个`AsyncExecutionRunnable`对象,将任务执行逻辑封装在其中。


接着,通过调用任务执行器的`execute()`方法,将`AsyncExecutionRunnable`对象提交给任务执行器执行。任务执行器在内部会从线程池中获取一个空闲的线程,并执行`run()`方法中的异步方法调用。


当异步方法执行完成或出现异常时,任务执行器会进行相应的处理。


通过以上源码,可以看出代理对象在调用异步方法时,会将异步方法的执行请求封装成一个`Runnable`或`Callable`的任务,并提交给任务执行器来执行。这样就实现了异步方法的调用和执行。


### 异步任务的执行

任务执行器会从线程池中获取一个空闲的线程来执行异步任务。异步任务的执行可能会被放入线程池的任务队列中,直到有线程可用为止。


### 异步方法的返回值处理

如果异步方法有返回值,代理对象会返回一个Future对象,用于获取异步方法执行的结果。你可以通过Future对象来获取异步方法的返回值或处理异常。


## 更多异步线程池的库或框架

除了使用`@Async`注解和自定义线程池外,在Spring框架中,还可以结合其他异步线程池的库或框架来实现异步任务的执行。以下是一些常见的异步线程池的库或框架:


### Guava

Guava是Google提供的Java工具库,其中包含了一个`ListeningExecutorService`接口,可以将`ExecutorService`转换为支持异步操作的执行器。


### CompletableFuture

`CompletableFuture`是Java 8引入的一个类,提供了一种方便的方式来执行异步任务。可以结合`CompletableFuture`和`Executor`来实现异步任务的执行。


#### 用法

`CompletableFuture`是Java 8中引入的一个类,用于支持异步编程和处理异步任务的结果。它提供了一种方便的方式来处理异步操作,并支持将多个异步任务组合在一起。下面是`CompletableFuture`的一些常用用法以及如何与Spring Boot一起使用:


1. 创建一个异步任务:

   ```java

   CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {

       // 异步任务的逻辑

       return "Hello, World!";

   });

   ```


2. 调用异步任务的结果:

   ```java

   future.thenAccept(result -> {

       // 处理异步任务的结果

       System.out.println(result);

   });

   ```


3. 组合多个异步任务:

   ```java

   CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");

   CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");


   CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> result1 + " " + result2);


   combinedFuture.thenAccept(result -> {

       // 处理组合异步任务的结果

       System.out.println(result);

   });

   ```


4. 异步任务的异常处理:

   ```java

   CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {

       // 异步任务的逻辑

       throw new RuntimeException("Something went wrong");

   });


   future.exceptionally(ex -> {

       // 处理异步任务的异常

       System.err.println("Exception: " + ex.getMessage());

       return 0; // 设置默认值

   });

   ```

#### 与springboot集成

与Spring Boot一起使用`CompletableFuture`时,你可以将异步任务作为Spring Bean的方法,并使用`@Async`注解进行标记,以便在Spring容器中进行管理和调用。以下是一个示例:


1. 在Spring Boot应用程序的配置类中,启用异步支持:

   ```java

   @Configuration

   @EnableAsync

   public class AppConfig {

       // 配置其他Bean和设置


       // 声明异步任务执行器

       @Bean

       public Executor asyncExecutor() {

           ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

           // 配置线程池参数

           // ...

           return executor;

       }

   }

   ```


2. 在Spring Bean中定义一个异步方法,使用`CompletableFuture`进行异步操作:

   ```java

   @Service

   public class MyService {

       @Async

       public CompletableFuture<String> doAsyncTask() {

           CompletableFuture<String> future = new CompletableFuture<>();

           // 异步任务的逻辑

           // ...

           return future;

       }

   }

   ```


3. 在其他组件中调用异步方法,并处理异步结果:

   ```java

   @RestController

   public class MyController {

       @Autowired

       private MyService myService;


       @GetMapping("/async")

       public ResponseEntity<CompletableFuture<String>> asyncEndpoint() {

           CompletableFuture<String> future = myService.doAsyncTask();

           return ResponseEntity.ok(future);

       }

   }

   ```


通过将异步任务定义为Spring Bean中的方法,并使用`@Async`注解进行标记,Spring Boot将自动为这些方法创建异步代理,使它们能够在单独的线程中执行。然后,你可以在其他组件中调用这些异步方法,并使用`CompletableFuture`来处理异步任务的结果。


#### 在异步操作时,相比于`Executors.newSingleThreadExecutor().submit`,使用`CompletableFuture.supplyAsync`的优势

相比于`Executors.newSingleThreadExecutor().submit`,使用`CompletableFuture.supplyAsync`有以下几个好处:


1. 异步任务的创建和执行更加简洁:使用`CompletableFuture.supplyAsync`可以直接将异步任务的逻辑封装在Lambda表达式中,并将其作为参数传递给方法。这样可以更加简洁地创建和执行异步任务,而不需要显式地创建`Executor`和`Callable`对象。


2. 支持更多的组合和链式操作:`CompletableFuture`提供了丰富的方法来处理异步任务的结果。你可以使用`thenApply`、`thenAccept`、`thenCombine`等方法来对异步任务的结果进行转换、处理和组合。这使得在异步任务之间进行链式操作和数据流转变变得更加便捷。


3. 支持异常处理和超时控制:`CompletableFuture`提供了方法来处理异步任务的异常情况,如`exceptionally`、`handle`等。它还支持设置异步任务的超时时间,通过`get`方法的重载版本来控制等待异步结果的超时时间。这样可以更好地管理和处理异步任务中可能出现的异常和超时情况。


4. 更灵活的执行器选择:`CompletableFuture`允许你传入自定义的执行器(`Executor`)来执行异步任务。这样你可以根据需求选择不同类型的执行器,如固定大小线程池、缓存线程池等,以满足特定的并发需求。


5. 支持函数式编程:`CompletableFuture`采用了函数式编程的风格,通过方法链式调用和Lambda表达式来组织异步任务的逻辑。这种风格更加符合现代Java开发的趋势,并提供了更高的可读性和可维护性。


综上所述,使用`CompletableFuture.supplyAsync`相比于`Executors.newSingleThreadExecutor().submit`具有更多的优势,能够提供更灵活、更简洁、更可组合的异步任务编程方式。


### Apache Commons

Apache Commons库提供了`ExecutorService`的实现,例如`BasicThreadFactory`和`DefaultExecutorServiceFactory`,可以用于创建和配置线程池。


#### `BasicThreadFactory`

它是一个简单的线程工厂,用于创建线程并配置其属性。你可以使用它来自定义线程的命名、优先级、守护状态等。


   示例代码:

   ```java

   import org.apache.commons.lang3.concurrent.BasicThreadFactory;


   // 创建线程池

   ExecutorService executor = Executors.newFixedThreadPool(10,

           new BasicThreadFactory.Builder()

                   .namingPattern("my-pool-thread-%d")

                   .daemon(false)

                   .priority(Thread.NORM_PRIORITY)

                   .build());

   // 执行任务

   executor.execute(() -> {

       // 异步任务逻辑

   });

   ```


#### `DefaultExecutorServiceFactory`

它是一个用于创建`ExecutorService`实例的工厂类。你可以使用它来创建具有自定义属性的`ExecutorService`,如核心线程数、最大线程数、线程存活时间等。


   示例代码:

   ```java

   import org.apache.commons.lang3.concurrent.DefaultExecutorServiceFactory;


   // 创建线程池工厂

   DefaultExecutorServiceFactory factory = new DefaultExecutorServiceFactory();

   factory.setMaximumPoolSize(10); // 设置最大线程数

   factory.setThreadNamePrefix("my-pool-thread-"); // 设置线程名前缀


   // 创建线程池

   ExecutorService executor = factory.createExecutorService();


   // 执行任务

   executor.execute(() -> {

       // 异步任务逻辑

   });

   ```


这些`ExecutorService`的实现类可以根据你的需求进行配置和使用,以满足不同的并发处理需求。可以根据自己的项目需要选择合适的实现类,并根据需要设置线程池的属性和配置。


### Netflix Hystrix

Hystrix是Netflix开发的容错库,提供了异步执行和线程池隔离等功能。它可以与Spring集成,用于处理异步任务的执行和容错机制。


这些库或框架提供了更多的功能和选项,可以根据具体需求选择合适的异步线程池库或框架来实现异步任务的执行。在Spring中,可以通过配置或自定义`TaskExecutor`来集成这些库或框架,并使用它们来执行异步任务。


Spring框架中的线程池的评论 (共 条)

分享到微博请遵守国家法律