JAVA多线程实战

背景

由于项目上要和其他系统交互,而该系统采用同步接口,我们采用单线程调用,接收一条数据平均需要4~6s。而我们需要汇总近三个月的订单信息,大约一次有几千条数据,所以进行一次交互大概需要几百分钟。经过沟通后,对方系统不愿意修改他们的程序,所以我们这边就要改成多线程多次同时调用接口,来达到降低处理时间的效果。

代码

话不多说,先上代码

public ReturnT execute(Map<String, String> map, SchedulerTool tool) {
        tool.info("<==== MakeOrderOutJob is starting: " + map);

        //获取最大线程数
        int threadNum = Integer.parseInt(map.get("threadNum"));

        //获取线程结束超时时间
        int timeOut = Integer.parseInt(map.get("timeOut"));

        //获取传输最大条数
        int max = Integer.parseInt(map.get("max"));

        //获取待发送的生产订单数据
        List<MakeOrder> makeOrderList = makeOrderRepository.getMakeOrder(max);
        tool.info("<==== MakeOrderOutJob makeOrderList size: " + makeOrderList.size());

        //返回消息集合
        List<MakeOrderReturnVO> makeOrderReturnVoList = new ArrayList<>();

        try {
            //手动创建线程池
            ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build();
            ExecutorService executor = new ThreadPoolExecutor(threadNum, threadNum, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), namedThreadFactory);
            //循环所有待传出数据,调用接口
            makeOrderList.stream().forEach(one -> {
                executor.execute(new ThreadPoolMakeOrderOutTask(tool, user, password, url, one, moRequirementRepository.getMoRequirementList(one.getKid()), makeOrderReturnVoList, restUtil, makeOrderRepository));
            });
            executor.shutdown();
            while (!executor.awaitTermination(timeOut, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }

            tool.info("<==== MakeOrderOutJob makeOrderReturnVoList size: " + makeOrderReturnVoList.size());
            //循环返回结果更新接口表
            makeOrderReturnVoList.stream().forEach((vo) -> {
                tool.info("<==== MakeOrderOutJob update status: " + vo.getMessageV1());
                //更新接口表状态
                vo.setStatus(vo.getType());
                tool.info("<==== MakeOrderOutJob update status success: " + vo.getMessageV1());
            });
        } catch (Exception e) {
            e.printStackTrace();
            tool.error("<==== MakeOrderOutJob is error: " + e.getMessage());
            return ReturnT.FAILURE;
        }
        return ReturnT.SUCCESS;
    }

总结

这里用到了线程池ExecutorService

1.线程的创建

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }

线程池一共有五种

  1. newCachedThreadPool:用来创建一个可以无限扩大的线程池
  2. newFixedThreadPool:创建一个固定大小的线程池
  3. newSingleThreadExecutor:创建一个单线程的线程池
  4. newScheduledThreadPool:可以延时启动,定时启动的线程池
  5. newWorkStealingPool:创建一个拥有多个任务队列的线程池

经BD后发现所有的线程池最终都是通过ThreadPoolExecutor创建的
其中各个参数说明:

corePoolSize : 核心线程数,一旦创建将不会再释放。如果创建的线程数还没有达到指定的核心线程数量,将会继续创建新的核心线程,直到达到最大核心线程数后,核心线程数将不在增加;如果没有空闲的核心线程,同时又未达到最大线程数,则将继续创建非核心线程;如果核心线程数等于最大线程数,则当核心线程都处于激活状态时,任务将被挂起,等待空闲线程来执行。
maximumPoolSize : 最大线程数,允许创建的最大线程数量。如果最大线程数等于核心线程数,则无法创建非核心线程;如果非核心线程处于空闲时,超过设置的空闲时间,则将被回收,释放占用的资源。
keepAliveTime : 当线程空闲时,所允许保存的最大时间,超过这个时间,线程将被释放销毁,但只针对于非核心线程。
unit : 时间单位,TimeUnit.SECONDS等。
workQueue : 任务队列,存储暂时无法执行的任务,等待空闲线程来执行任务。
threadFactory :  线程工程,用于创建线程。本例用到new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build();来为线程创建名称。
handler : 当线程边界和队列容量已经达到最大时,用于处理阻塞时的程序

2.创建好了线程后就要执行任务,实现多线程有三种方法

继承Thread类,重写run方法
实现Runnable接口,重写run方法
实现Callable接口,重写call方法(有返回值)

本例中ThreadPoolMakeOrderOutTask用到了第2种方法

3.任务执行完毕,要结束线程池任务

本例调用shutdown() 方法在终止前允许执行以前提交的任务,shutdown()方法的作用是:停止接收新任务,原来的任务继续执行

然后调用awaitTermination(long timeOut, TimeUnit unit)方法,使当前线程阻塞,直到:

等所有已提交的任务(包括正在跑的和队列中等待的)执行完
或者 等超时时间到了(timeout 和 TimeUnit设定的时间)
或者 线程被中断,抛出InterruptedException

然后会监测 ExecutorService 是否已经关闭,返回true(shutdown请求后所有任务执行完毕)或false(已超时)

最后调用shutdownNow()方法,停止接收新任务,原来的任务停止执行

结果

经测试,启用多线程后,发现交互时间确实有明显提升。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值