SpringBoot中使用多线程的方法示例

网友投稿 1309 2023-02-05

SpringBoot中使用多线程的方法示例

SpringBoot中使用多线程的方法示例

一、介绍

Spring是通过任务执行器(TaskExecutor)来实现多线程和并发编程,使用Spring提供的ThreadPoolTaskExecutor来创建一个基于线城池的TaskExecutor。在使用线程池的大多数情况下都是异步非阻塞的。节省更多的时间,提高效率。

工作原理

当主线程中调用execute接口提交执行任务时:则执行以下步骤:注意:线程池初始时,是空的。

如果当前线程数

如果当前线程数>=corePoolSize,则将任务存入BlockingQueue

如果阻塞队列已满,且当前线程数

如果阻塞队列已满,且当前线程数>=maximumPoolSize,则抛出异常RejectedExecutionException,告诉调用者无法再接受任务了。

在Springboot中对其进行了简化处理,只需要配置一个类型为java.util.concurrent.TaskExecutor或其子类的bean,并在配置类或直接在程序入口类上声明注解@EnableAsync,即可可以开启异步任务。

调用也简单,在由Spring管理的对象的方法上标注注解@Async,声明是异步任务,显式调用即可生效。

二、声明

让配置类实现AsyncConfigurer接口,并重写getAsyncExecutor方法,并返回一个ThreasPoolTaskExecutor,就可以获取一个基于线程池的TaskExecutor

使用注解@EnableAsync开启异步,会自动扫描

@Configuration

@EnableAsync

public class ThreadConfig implements AsyncConfigurer {

@Override

public Executor getAsyncExecutor() {

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

executor.setCorePoolSize(5);

executor.setMaxPoolSize(15);

executor.setQueueCapacity(25);

executor.initialize();

return executor;

}

@Override

public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

return null;

}

}

三、调用

通过@Async注解表明该方法是异步方法,如果注解在类上,那表明这个类里面的所有方法都是异步的

@Service

public class AsyncTaskService {

@Async

public void executeAsyncTask(int i) {

System.out.println("线程" + Thread.currentThread().getName() + " 执行异步任务:" + i);

}

}

四、进阶

有时候我们不止希望异步执行任务,还希望任务执行完成后会有一个返回值,在java中提供了Future泛型接口,用来接收任务执行结果,springboot也提供了此类支持,使用实现了ListenableFuture接口的类如AsyncResult来作为返回值的载体。比如上例中,我们希望返回一个类型为String类型的值,可以将返回值改造为:

@Async

public Future executeAsyncTaskWithResult2(int i) {

System.out.println("线程" + Thread.currentThread().getName() + " 开始执行异步任务" + i);

try {

Threhttp://ad.sleep(10000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("线程" + Thread.currentThread().getName() + " 结束执行异步任务" + i);

return new AsyncResult<>("线程" + Thread.currentThread().getName() + " 执行异步任务:" + i);

}

调用返回值:

get()是阻塞式,等待当前线程完成才返回值

public void threadTest() {

try {

List futures = new ArrayList<>();

for (int i = 0; i < 20; i++) {

futures.add(asyncTaskService.executeAsyncTaskWithResult2(i));

}

// 获取值。get是阻塞式,等待当前线程完成才返回值

for (Future future : futures) {

System.out.println("返回结果:" + future.get());

}

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}

}

补充

实际上,@Async还有一个参数,通过Bean名称来指定调用的线程池-比如上例中设置的线程池参数不满足业务需求,可以另外定义合适的线程池,调用时指明使用这个线程池-缺省时springboot会优先使用名称为'taskExecutor'的线程池,如果没有找到,才会使用其他类型为TaskExecutor或其子类的线程池。

如果当前线程数>=corePoolSize,则将任务存入BlockingQueue

如果阻塞队列已满,且当前线程数

如果阻塞队列已满,且当前线程数>=maximumPoolSize,则抛出异常RejectedExecutionException,告诉调用者无法再接受任务了。

在Springboot中对其进行了简化处理,只需要配置一个类型为java.util.concurrent.TaskExecutor或其子类的bean,并在配置类或直接在程序入口类上声明注解@EnableAsync,即可可以开启异步任务。

调用也简单,在由Spring管理的对象的方法上标注注解@Async,声明是异步任务,显式调用即可生效。

二、声明

让配置类实现AsyncConfigurer接口,并重写getAsyncExecutor方法,并返回一个ThreasPoolTaskExecutor,就可以获取一个基于线程池的TaskExecutor

使用注解@EnableAsync开启异步,会自动扫描

@Configuration

@EnableAsync

public class ThreadConfig implements AsyncConfigurer {

@Override

public Executor getAsyncExecutor() {

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

executor.setCorePoolSize(5);

executor.setMaxPoolSize(15);

executor.setQueueCapacity(25);

executor.initialize();

return executor;

}

@Override

public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

return null;

}

}

三、调用

通过@Async注解表明该方法是异步方法,如果注解在类上,那表明这个类里面的所有方法都是异步的

@Service

public class AsyncTaskService {

@Async

public void executeAsyncTask(int i) {

System.out.println("线程" + Thread.currentThread().getName() + " 执行异步任务:" + i);

}

}

四、进阶

有时候我们不止希望异步执行任务,还希望任务执行完成后会有一个返回值,在java中提供了Future泛型接口,用来接收任务执行结果,springboot也提供了此类支持,使用实现了ListenableFuture接口的类如AsyncResult来作为返回值的载体。比如上例中,我们希望返回一个类型为String类型的值,可以将返回值改造为:

@Async

public Future executeAsyncTaskWithResult2(int i) {

System.out.println("线程" + Thread.currentThread().getName() + " 开始执行异步任务" + i);

try {

Threhttp://ad.sleep(10000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("线程" + Thread.currentThread().getName() + " 结束执行异步任务" + i);

return new AsyncResult<>("线程" + Thread.currentThread().getName() + " 执行异步任务:" + i);

}

调用返回值:

get()是阻塞式,等待当前线程完成才返回值

public void threadTest() {

try {

List futures = new ArrayList<>();

for (int i = 0; i < 20; i++) {

futures.add(asyncTaskService.executeAsyncTaskWithResult2(i));

}

// 获取值。get是阻塞式,等待当前线程完成才返回值

for (Future future : futures) {

System.out.println("返回结果:" + future.get());

}

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}

}

补充

实际上,@Async还有一个参数,通过Bean名称来指定调用的线程池-比如上例中设置的线程池参数不满足业务需求,可以另外定义合适的线程池,调用时指明使用这个线程池-缺省时springboot会优先使用名称为'taskExecutor'的线程池,如果没有找到,才会使用其他类型为TaskExecutor或其子类的线程池。

如果阻塞队列已满,且当前线程数>=maximumPoolSize,则抛出异常RejectedExecutionException,告诉调用者无法再接受任务了。

在Springboot中对其进行了简化处理,只需要配置一个类型为java.util.concurrent.TaskExecutor或其子类的bean,并在配置类或直接在程序入口类上声明注解@EnableAsync,即可可以开启异步任务。

调用也简单,在由Spring管理的对象的方法上标注注解@Async,声明是异步任务,显式调用即可生效。

二、声明

让配置类实现AsyncConfigurer接口,并重写getAsyncExecutor方法,并返回一个ThreasPoolTaskExecutor,就可以获取一个基于线程池的TaskExecutor

使用注解@EnableAsync开启异步,会自动扫描

@Configuration

@EnableAsync

public class ThreadConfig implements AsyncConfigurer {

@Override

public Executor getAsyncExecutor() {

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

executor.setCorePoolSize(5);

executor.setMaxPoolSize(15);

executor.setQueueCapacity(25);

executor.initialize();

return executor;

}

@Override

public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

return null;

}

}

三、调用

通过@Async注解表明该方法是异步方法,如果注解在类上,那表明这个类里面的所有方法都是异步的

@Service

public class AsyncTaskService {

@Async

public void executeAsyncTask(int i) {

System.out.println("线程" + Thread.currentThread().getName() + " 执行异步任务:" + i);

}

}

四、进阶

有时候我们不止希望异步执行任务,还希望任务执行完成后会有一个返回值,在java中提供了Future泛型接口,用来接收任务执行结果,springboot也提供了此类支持,使用实现了ListenableFuture接口的类如AsyncResult来作为返回值的载体。比如上例中,我们希望返回一个类型为String类型的值,可以将返回值改造为:

@Async

public Future executeAsyncTaskWithResult2(int i) {

System.out.println("线程" + Thread.currentThread().getName() + " 开始执行异步任务" + i);

try {

Threhttp://ad.sleep(10000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("线程" + Thread.currentThread().getName() + " 结束执行异步任务" + i);

return new AsyncResult<>("线程" + Thread.currentThread().getName() + " 执行异步任务:" + i);

}

调用返回值:

get()是阻塞式,等待当前线程完成才返回值

public void threadTest() {

try {

List futures = new ArrayList<>();

for (int i = 0; i < 20; i++) {

futures.add(asyncTaskService.executeAsyncTaskWithResult2(i));

}

// 获取值。get是阻塞式,等待当前线程完成才返回值

for (Future future : futures) {

System.out.println("返回结果:" + future.get());

}

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}

}

补充

实际上,@Async还有一个参数,通过Bean名称来指定调用的线程池-比如上例中设置的线程池参数不满足业务需求,可以另外定义合适的线程池,调用时指明使用这个线程池-缺省时springboot会优先使用名称为'taskExecutor'的线程池,如果没有找到,才会使用其他类型为TaskExecutor或其子类的线程池。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:MyBatis控制台显示SQL语句的方法实现
下一篇:服装搭配app运营模式(服装搭配app商业模式)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~