异步线程池的使用

Posted gaopengfirst

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异步线程池的使用相关的知识,希望对你有一定的参考价值。

合理使用异步线程开发项目能提高一个项目的并发量,减少响应时间。下面就简单介绍一下异步线程池的使用,参考博客:https://blog.csdn.net/hry2015/article/details/67640534

spring 对@Async定义异步任务的方法有3种:

1.最简单的异步调用,返回值为void;

2.带参数的异步调用,异步方法可以传入参数;

3.异常调用返回Future

代码如下:

package com.hry.spring.async.annotation;

import java.util.concurrent.Future;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;

/**
 * 异步方法调用
 * 
 * @author hry
 *
 */
@Component
public class AsyncDemo {
	private static final Logger log = LoggerFactory.getLogger(AsyncDemo.class);

	/**
	 * 最简单的异步调用,返回值为void
	 */
	@Async
	public void asyncInvokeSimplest() {
		log.info("asyncSimplest");
	}

	/**
	 * 带参数的异步调用 异步方法可以传入参数
	 * 
	 * @param s
	 */
	@Async
	public void asyncInvokeWithParameter(String s) {
		log.info("asyncInvokeWithParameter, parementer={}", s);
	}

	/**
	 * 异常调用返回Future
	 * 
	 * @param i
	 * @return
	 */
	@Async
	public Future<String> asyncInvokeReturnFuture(int i) {
		log.info("asyncInvokeReturnFuture, parementer={}", i);
		Future<String> future;
		try {
			Thread.sleep(1000 * 1);
			future = new AsyncResult<String>("success:" + i);
		} catch (InterruptedException e) {
			future = new AsyncResult<String>("error");
		}
		return future;
	}

}

  

spring启动配置的方式有两种:

1.注解;

2.XML配置文件

我们先说注解的方式:

@EnableAsync注解可以开启异步调用功能, public AsyncTaskExecutor taskExecutor() 方法自定义自己的线程池,线程池前缀”Anno-Executor”。如果不定义,则使用系统默认的线程池。代码如下:

package com.hry.spring.async.annotation;

import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * 通过@EnableAsync启动异步方法
 * @author hry
 * 
 */
@SpringBootApplication
@EnableAsync // 启动异步调用
public class AsyncApplicationWithAnnotation {
	private static final Logger log = LoggerFactory.getLogger(AsyncApplicationWithAnnotation.class);
	
	/**
	 * 自定义异步线程池
	 * 	如果没有这个方法,则使用默认的线程池
	 * @return
	 */
    @Bean
    public AsyncTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setThreadNamePrefix("Anno-Executor");//设置线程名称的前缀
        executor.setCorePoolSize(5);//设置核心线程数
        executor.setMaxPoolSize(10);//设置最大线程数

        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new RejectedExecutionHandler() {
			@Override
			public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
				// .....
			}
		});
        // 使用预定义的异常处理类
        // executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        return executor;
    }
    
	public static void main(String[] args) {
		log.info("Start AsyncApplication.. ");
		SpringApplication.run(AsyncApplicationWithAnnotation.class, args);
	}
}

 现在写测试类:

package com.hry.spring.async.annotation;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.hry.spring.async.annotation.AsyncApplicationWithAnnotation;
import com.hry.spring.async.annotation.AsyncDemo;

@RunWith(SpringRunner.class)
@SpringBootTest(classes=AsyncApplicationWithAnnotation.class)
public class AsyncApplicationWithAnnotationTests {
	@Autowired
	private AsyncDemo asyncDemo;
	
	@Test
	public void contextLoads() throws InterruptedException, ExecutionException {
		asyncDemo.asyncInvokeSimplest();
		asyncDemo.asyncInvokeWithParameter("test");
		Future<String> future = asyncDemo.asyncInvokeReturnFuture(1000);
		System.out.println(future.get());
	}
}

 启动测试类,结果如下:

技术图片

说明启动异步线程池成功,执行上面的3个方法分别用了3个线程。

再说一下XML配置文件配置的方式:

我们先创建XML配置文件:

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:tx="http://www.springframework.org/schema/tx"  
    xmlns:task="http://www.springframework.org/schema/task"  
    xsi:schemaLocation="  
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  
        http://www.springframework.org/schema/context   
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd  
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"  
    default-lazy-init="false">  
    
  	<!-- 等价于 @EnableAsync, executor指定线程池 -->
  	<task:annotation-driven executor="xmlExecutor"/>
  	<!-- id指定线程池产生线程名称的前缀 -->
    <task:executor
        id="xmlExecutor"
        pool-size="3-20"
        queue-capacity="100"
	    keep-alive="120"
        rejection-policy="CALLER_RUNS"/>
	
</beans>

  

其中id表示线程名称的前缀,pool-size表示线程池的大小,“3-20”表示线程池的最大线程数为20,最小线程数为3,也可以设置成一个值,如:pool-size=5,则表示线程池的核心线程数和最大线程数相同,都是5。queue-capacity表示排队队列的长度。

项目启动时读取xml配置文件,如下:

package com.hry.spring.async.xml;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;


/**
 * 通过XML启动异步
 * @author hry
 *
 */
@SpringBootApplication
@ImportResource("classpath:/async/spring_async.xml")
public class AsyncApplicationWithXML {
	private static final Logger log = LoggerFactory.getLogger(AsyncApplicationWithXML.class);
	
	public static void main(String[] args) {
		log.info("Start AsyncApplication.. ");
		SpringApplication.run(AsyncApplicationWithXML.class, args);
	}
}  

 

编写测试类:

package com.hry.spring.async.xml;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
 
@RunWith(SpringRunner.class)
@SpringBootTest(classes=AsyncApplicationWithXML.class)
public class AsyncApplicationWithXMLTest {
	@Autowired
	private AsyncDemo asyncDemo;

	@Test
	public void contextLoads() throws InterruptedException, ExecutionException {
		asyncDemo.asyncInvokeSimplest();
		asyncDemo.asyncInvokeWithParameter("test");
		Future<String> future = asyncDemo.asyncInvokeReturnFuture(100);
		System.out.println(future.get());
	}
}

  

测试结果如下:

技术图片

测试成功。

 

 

以上是关于异步线程池的使用的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot中有多个@Async异步任务时,记得做好线程池的隔离!

Spring Boot中有多个@Async异步任务时,记得做好线程池的隔离!

在 .NET / .NET Core 中的异步 I/O 期间,线程池的完成端口线程如何表现?

线程池的设计思想

你可能写了个假异步,并不能提高请求线程池的吞吐量

newCacheThreadPool()newFixedThreadPool()newScheduledThreadPool()newSingleThreadExecutor()自定义线程池(代码片段