SpringBoot进阶篇5:springboot下的多线程

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;
}

猜你喜欢

转载自blog.csdn.net/u013089490/article/details/87983634