线程池的使用

1、重要参数

  1. 核心线程数(corePoolSize):当线程池的线程都忙碌时,再进来新任务时,由最小线程数扩容到核心线程数 。一般设置为cpu的核数

  2. 最大线程数 (maximumPoolSize):当核心线程数满了,当队列也满了,再来新任务,就会创建新非核心线程来执行这个新任务,直到线程数达到最大线程数。一般设置为cpu的核数*2

  3. 存活时间(keepAliveTime):非核心线程 =(maximumPoolSize - corePoolSize ) ,非核心线程闲置下来不干活最多存活时间。当非核心线程超过多长时间不执行任务,处于空闲状态,线程池会将它回收,直到线程数量达到核心线程数。如果设置为0,就代表不回收

  4. 存活时间单位(unit):线程池中非核心线程保持存活的时间的单位

TimeUnit.DAYS; 天
TimeUnit.HOURS; 小时
TimeUnit.MINUTES; 分钟
TimeUnit.SECONDS; 秒
TimeUnit.MILLISECONDS; 毫秒
TimeUnit.MICROSECONDS; 微秒
TimeUnit.NANOSECONDS; 纳秒

  1. 线程池等待队列(workQueue):维护着等待执行的Runnable对象。当运行当线程数= corePoolSize时,新的任务会被添加到workQueue中,如果workQueue也满了则尝试用非核心线程执行任务,等待队列应该尽量用有界的。
  2. threadFactory
    创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等。
  3. handler
    corePoolSize、workQueue、maximumPoolSize都不可用的时候执行的饱和策略

2、使用线程池的注意事项

线程池尽量不要使用的时候再创建,不要在业务逻辑里面去创建线程池,因为这样会在每次调用这个方法的时候,都会创建一个线程池。应该在项目启动的时候,就把线程池创建好。

3、使用场景及示例代码

  1. 任务来了,直接将任务交给线程池去做,至于成不成功、用不用返回值,不去关注。主要适用于一些更新操作,我不太关注执行结果或返回值。
    代码:起一个springboot项目
    线程池配置类,将线程池交给spring管理:
@Configuration
public class ThreadPoolConfig {
    public static final String NAME_PRE = "test-";

    @Bean
    public static ExecutorService getExecutor(){

        return ExecutorBuilder.create()
                .setCorePoolSize(8)
                .setMaxPoolSize(16)
                .setKeepAliveTime(60, TimeUnit.SECONDS)
                .setHandler(new ThreadPoolExecutor.CallerRunsPolicy())
                .setWorkQueue(new LinkedBlockingDeque<>(2000))
                .setThreadFactory(ThreadFactoryBuilder.create().setNamePrefix(NAME_PRE).build())
                .setAllowCoreThreadTimeOut(false)
                .build();


    }
}

service:

public interface IUserService{
	void testThreadPool();
}

service实现类:

@Service
@Slf4j
public class IUserServiceImpl implements IUserService {
	//通过Resource注解将ExecutorService 的实现类也就是ThreadPoolConfig 中getExecutor返回的线程池对象。
	@Resource
	private ExecutorService executorService;

	@Override
    public void testThreadPool() {
		log.info("进来了");
        //交给线程池里的线程去执行
        CompletableFuture.runAsync(() -> {
            try {
                log.info("进来了1111");
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, executorService);
	}

controller:

@RequestMapping("/open/test")
    public ResultUtil test(){
        iUserService.testThreadPool();
        //主线程直接返回结果
        return ResultUtil.success("test");
    }

通过浏览器调用该接口,不用等待10s, 结果直接返回给浏览器

  1. 任务来了,将任务交给线程池去执行,等任务都执行完了 ,主线程才能解除阻塞,适用于
    • 自己的方法很复杂,需要多次查询数据库
      在这里插入图片描述

    • 需要循环调用http接口查询

    • 需要for循环查询数据库

代码:
起一个springboot项目
保存执行结果:

@Data
public class QueryBo {

    private Boolean query1;
    private Boolean query2;
    private Boolean query3;
}

线程池配置类,将线程池交给spring管理:

@Configuration
public class ThreadPoolConfig {
    public static final String NAME_PRE = "test-";

    @Bean
    public static ExecutorService getExecutor(){

        return ExecutorBuilder.create()
                .setCorePoolSize(8)
                .setMaxPoolSize(16)
                .setKeepAliveTime(60, TimeUnit.SECONDS)
                .setHandler(new ThreadPoolExecutor.CallerRunsPolicy())
                .setWorkQueue(new LinkedBlockingDeque<>(2000))
                .setThreadFactory(ThreadFactoryBuilder.create().setNamePrefix(NAME_PRE).build())
                .setAllowCoreThreadTimeOut(false)
                .build();


    }
}

service:

public interface IUserService{
	void testThreadPool();
}

service实现类:

@Service
@Slf4j
public class IUserServiceImpl implements IUserService {
	//通过Resource注解将ExecutorService 的实现类也就是ThreadPoolConfig 中getExecutor返回的线程池对象。
	@Resource
	private ExecutorService executorService;

	@Override
    public void testThreadPool() {
        log.info("进来了");
        QueryBo queryBo = new QueryBo();
        long start = System.currentTimeMillis();
        //将任务交给线程池里的线程去执行
        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
            Boolean aBoolean=null;
            try {
                aBoolean=query1();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            queryBo.setQuery1(aBoolean);
        }, executorService);


        //交给线程池里的线程去执行
        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            Boolean aBoolean=null;
            try {
                aBoolean=query2();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            queryBo.setQuery2(aBoolean);
        }, executorService);

        //交给线程池里的线程去执行
        CompletableFuture<Void> future3 = CompletableFuture.runAsync(() -> {
            Boolean aBoolean=null;
            try {
                aBoolean=query3();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            queryBo.setQuery3(aBoolean);
        }, executorService);

        //将上面的线程池任务装进数组
        CompletableFuture[]completableFutures = Stream.of(future1,future2,future3).collect(Collectors.toList()).toArray(new CompletableFuture[3]);
        //当数组里的所有交给线程池的任务都执行完后,才会继续向下执行;相当于阻塞
        CompletableFuture.allOf(completableFutures).join();
        
        long end=System.currentTimeMillis()- start;
        log.info("查询结果{},时间差{}",queryBo.toString(),end);
    }
	//任务1
    public boolean query1() throws InterruptedException {
        log.info("进来了1");
        Thread.sleep(1000);
        return true;
    }
	//任务2
    public boolean query2() throws InterruptedException {
        log.info("进来了2");
        Thread.sleep(3000);
        return true;
    }
	//任务3
    public boolean query3() throws InterruptedException {
        log.info("进来了3");
        Thread.sleep(5000);
        return true;
    }
}

controller:

@RequestMapping("/open/test")
    public ResultUtil test(){
        iUserService.testThreadPool();
        return ResultUtil.success("test");
    }

通过浏览器调用该接口,5s后,结果才返回给浏览器
通过日志可以观察到,这三个任务由原来串行化执行9s变为多线程并行执行5s

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值