java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring线程池ThreadPoolTaskExecutor用法

Spring线程池ThreadPoolTaskExecutor的用法及说明

作者:爱吃牛肉的大老虎

这篇文章主要介绍了Spring线程池ThreadPoolTaskExecutor的用法及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

1 线程池简介

1.1 为什么使用线程池

1.2 线程池为什么需要使用队列

1.3 线程池为什么要使用阻塞队列而不使用非阻塞队列

1.4 如何配置线程池

CPU密集型任务

IO密集型任务

混合型任务

1.5 execute()和submit()方法

1.execute(),执行一个任务,没有返回值

2.submit(),提交一个线程任务,有返回值

1.6 Spring线程池

Spring 通过任务执行器(TaskExecutor)来实现多线程和并发编程,使用ThreadPoolTaskExecutor实现一个基于线程池的TaskExecutor,

还得需要使用@EnableAsync开启异步,并通过在需要的异步方法那里使用注解@Async声明是一个异步任务

Spring 已经实现的异常线程池:

1.7 @Async调用中的事务处理机制

点击了解使用@Async使用的事务问题

2 示例

2.1 线程池配置类

package cn.jzh.thread;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
@ComponentScan("cn.jzh.thread")
@EnableAsync  //开启异步操作
public class TaskExecutorConfig implements AsyncConfigurer {
    /**
     * 通过getAsyncExecutor方法配置ThreadPoolTaskExecutor,获得一个基于线程池TaskExecutor
     *
     * @return
     */
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
        pool.setCorePoolSize(5);//核心线程数
        pool.setMaxPoolSize(10);//最大线程数
        pool.setQueueCapacity(25);//线程队列
        pool.initialize();//线程初始化
        return pool;
    }
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return null;
    }
}

配置类中方法说明:

Spring 中的ThreadPoolExecutor是借助JDK并发包中的java.util.concurrent.ThreadPoolExecutor来实现的。

其中一些值的含义如下:

当任务添加到线程池中之所以被拒绝,可能是由于:第一,线程池异常关闭。第二,任务数量超过线程池的最大限制。

Reject策略预定义有四种:

自定义策略:当然也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务

2.2 异步方法

@Async注解可以用在方法上,表示该方法是个异步方法,也可以用在类上,那么表示此类的所有方法都是异步方法

异步方法会自动注入使用ThreadPoolTaskExecutor作为TaskExecutor

package cn.jzh.thread;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.concurrent.Future;
@Service
public class AsyncTaskService {
    /**
     * 
     * @param i
     */
    @Async
    public void executeAsync(Integer i) throws Exception{
        System.out.println("线程ID:" + Thread.currentThread().getId() + "线程名字:" +Thread.currentThread().getName()+"执行异步任务:" + i);
    }
    @Async
    public Future<String> executeAsyncPlus(Integer i) throws Exception {
        System.out.println("线程ID:" + Thread.currentThread().getId() +"线程名字:" +Thread.currentThread().getName()+ "执行异步有返回的任务:" + i);
        return new AsyncResult<>("success:"+i);
    }
}

2.3 启动测试

package cn.jzh.thread;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.concurrent.Future;
public class MainApp {
    public static void main(String[] args) throws Exception{
        System.out.println("主线程id:" + Thread.currentThread().getId() + "开始执行调用任务...");
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TaskExecutorConfig.class);
        AsyncTaskService service = context.getBean(AsyncTaskService.class);
        for (int i = 0;i<10;i++){
            service.executeAsync(i);
            Future<String> result = service.executeAsyncPlus(i);
            System.out.println("异步程序执行结束,获取子线程返回内容(会阻塞当前main线程)" + result.get());
        }
        context.close();
        System.out.println("主线程id:" + Thread.currentThread().getId() + "程序结束!!");
    }
}

注意:

1.是否影响主线程

如果main主线程不去获取子线程的结果(Future.get()),那么主线程完全可以不阻塞。那么,此时,主线程和子线程完全异步。此功能,可以做成类似MQ消息中间件之类的,消息异步进行发送

2.判断是否执行完毕

当返回的数据类型为Future类型,其为一个接口。具体的结果类型为AsyncResult,这个是需要注意的地方。

调用返回结果的异步方法,判断是否执行完毕时需要使用future.isDone()来判断是否执行完毕

public void testAsyncAnnotationForMethodsWithReturnType()  
   throws InterruptedException, ExecutionException {  
    System.out.println("Invoking an asynchronous method. "   + Thread.currentThread().getName());  
    Future<String> future = asyncAnnotationExample.asyncMethodWithReturnType();  
    while (true) {  ///这里使用了循环判断,等待获取结果信息  
        if (future.isDone()) {  //判断是否执行完毕  
            System.out.println("Result from asynchronous process - " + future.get());  
            break;  
        }  
        System.out.println("Continue doing something else. ");  
        Thread.sleep(1000);  
    }  
}

这些获取异步方法的结果信息,是通过不停的检查Future的状态来获取当前的异步方法是否执行完毕来实现的

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文