1、线程池配置类
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 线程池配置类
*/
@Configuration
@EnableAsync
public class ExecutorConfig implements AsyncConfigurer {
/* private static Logger logger = LogManager.getLogger(ExecutorConfig.class.getName());*/
@Bean
public ThreadPoolTaskExecutor asyncServiceExecutor() {
//Runtime.getRuntime().availableProcessors()可用处理器的Java虚拟机的数量,也就是一个cpu的核数
//newFixedThreadPool,设置为固定线程
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数,默认是1个
executor.setCorePoolSize(10);
// 设置最大线程数
executor.setMaxPoolSize(30);
// 设置队列容量,也就是队列大小
executor.setQueueCapacity(300);
// 设置线程活跃时间(秒),默认是60秒
executor.setKeepAliveSeconds(40);
// 设置默认线程名称
executor.setThreadNamePrefix("creawler_");
// 设置拒绝策略
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行;CallerRunsPolicy,用于被拒绝任务的处理程序,它直接在execute方法的调用线程中运行被拒绝的任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
//加载
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
注意在该配置类上的@EnableAsync注解表示开启线程池,否则不生效。
2、配置线程池异步服务
import cn.jun.eps.dao.CrawlerDataDao;
import cn.jun.eps.entity.CrawlerData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.concurrent.CountDownLatch;
/**
* @ClassName AsyncService
* @描述 异步任务服务
**/
@Service
public class AsyncService {
@Autowired
private CrawlerDataDao crawlerDao;
@Resource
private RedisTemplate<String, Object> redisOptions;
@Async("asyncServiceExecutor")
public void insertCrawler(CrawlerData crawler,CountDownLatch countDownLatch){
try{
// System.out.println("线程-"+Thread.currentThread().getId()+"在执行写入数据库操作开始");
crawlerDao.save(crawler);
}catch (Exception e){
e.printStackTrace();
//把异常的crawler记录下。
System.err.println("异常:"+crawler.toString());
// redisOptions.opsForValue().set(countDownLatch.);
}finally {
// System.err.println("线程-"+Thread.currentThread().getId()+"在执行写入数据库操作完成");
//写入完后减1
countDownLatch.countDown();
}
}
}
注意方法上的@Async("asyncServiceExecutor")这个注解的使用。
3、如何使用线程池
1、在其他service层中注入异步任务服务
@Autowired
AsyncService asyncService;
2、定义countDownLatch
private static CountDownLatch countDownLatch;
3、在这个service层中使用
/**
* 保存数据
* @param crawlerList
*/
public int savaData(List<CrawlerData> crawlerList){
int count=0;
try {
//注意设置CountDownLatch大小
countDownLatch = new CountDownLatch(crawlerList.size());
crawlerList.forEach(crawlerData -> {
asyncService.insertCrawler(crawlerData,countDownLatch);
}
);
//阻塞,这个地方需要特别注意
countDownLatch.await();
}catch (Exception e){
e.printStackTrace();
}
count=crawlerList.size();
return count;
}
4、实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Entity
@Table(name = "crawlerdata")
public class CrawlerData implements Serializable {
@Id
private Long id;
private String year;
@Column(name="indicator_code")
private String indicatorcode;
private String name;
@Column(name="data_value")
private String dataValue;
@Column(name = "cube_id")
private String cubeId;
@Column(name="region_code")
private String regionCode;
@Column(name = "region_name")
private String regionName;
}