Java生产环境线程池使用场景

talk is cheap, show me the code 直接上代码

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author by bixi.lx
 * @created on 2018 07 28 22:17
 */
public class ThreadPoolProduction {

    public static void main(String[] args) {

        BussinessService bussinessService = new BussinessServiceImpl();

        //新建一个线程池,池中有两个线程,注意这里使用的是fiexd 注意和cached的区别
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        //注意这里使用的是callable 而不是runable。
        ArrayList<Callable<Integer>> tasks = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            tasks.add(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    bussinessService.handleBussiness();
                    return 0;
                }
            });
        }

        try {
            //由于我们使用的是callable,所以在执行完成后,会拿到反馈信息,而runable不可以
            List<Future<Integer>> futures = executorService.invokeAll(tasks);
            for (Future<Integer> future : futures) {
                System.out.println(future.get());
            }
        } catch (ExecutionException e) {
            //这里生产环境不可以这么写,不要生吞(swallow)异常,处理的方式有很多种,比如可以向日志系统追加日志
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

首先,新建了一个线程池,注意这个线程池是fixed的(线程池创建主要由四种方式,具体哪四种,我还真不记得了,阿里的面试问到了, 印象非常深的记住了两种,就是fixed和cached,当时回答了这两个的区别,并且讲了下fixed的缺点,后面我们会深入讲解这个。)

其次,我们新建了一个任务的列表tasks(注意这个列表的泛型是callable)

最后,我们提交批量执行这个任务,由于线程池中只有两个线程,所以会看见每次都是打印出两行。(执行这里是最关键的,因为之前我们的任务都是基于callable的,所以执行之后会返回一个future,future大家都熟悉了,项目中也有使用到,使用的场景就是处理完成之后会返回一个回执内容。)

项目中要看具体的业务场景了,由于报表项目是使用mysql来使用数据库的资源进行计算的,根据生产环境的服务器和rds mysql数据的连接资源,所以最适合不过使用fixed的线程池了,报表,计算数据的时候,出错了就出错了,大不了重新算,所以现在的生产环境中,拿到callable执行后的结果也并没有做任何的处理。这里就有人会问了,如果真的出错了怎么办,又没有拿到错误的信息,都不会知道是不是出现了错误,实际上如果报表在计算任务中出现了失败,那么会在具体的业务代码中,记录失败的日志信息到es,显示在kibana中。当然,实际上,就算是没有记录错误信息,出现了错误没被发现,也不会有太大的问题。很多时候,恰巧不解决,反而降低了实现的复杂度,因为在报表的业务实现上,做了一些设计,哪怕是出错了,也没关系的。至于这些设计是哪些,后面我会找时间整理出来。

下图是程序运行过程中,线程的使用情况,可以看到pool-1 线程池中有2 similar threads, 分别是pool-1-thread-2 pool-1-thread-1两个线程当前没有要处理的任务,处于等待状态

/**
 * @author by bixi.lx
 * @created on 2018 07 28 22:51
 */
public interface BussinessService {

    void handleBussiness();
}
/**
 * @author by bixi.lx
 * @created on 2018 07 28 22:52
 */
public class BussinessServiceImpl implements BussinessService {

    @Override
    public void handleBussiness() {
        System.out.println("处理业务逻辑");

        // 为了观察线程是根据线程池设置的线程数,批量执行的,这里加上线程休眠
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/u010372981/article/details/81266755