Java 线程池关闭

Posted Mercy互动分享

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 线程池关闭相关的知识,希望对你有一定的参考价值。


    虽然使用ExecutorService可以让线程处理变的很简单,可是有没有人觉得在结束线程运行时候只调用shutdown方法就可以了?
    实际上,只调用shutdown方法的是不够的。我们用学校的老师和学生的关系来说明这个问题。
    shutdown只是起到通知的作用
    
     
    
    我们来假设如下场景:
    学校里在课上老师出了一些问题安排全班同学进行解答并对学生说“开问题解答完毕后请举手示意!”
    如果有学生解答完毕后会举手对老师说“老师我做完了!”,如果大家都解题完毕后上课结束。
    
    上面的场景对应于ExecutorService里的方法的话是下面的样子。
    老师: ExecutorService
    学生: ExecutorService里的线程
    问题: 通过参数传递给ExecutorService.execute的任务(Runnable)
    授课: main线程
    学校: Java进程
    
     
    
    “问题解答完毕后请举手示意!”是shutdown方法。“老师我做完了!”是各个任务(Runnable)的运行结束。

    所有的任务(Runnable)都结束了的话main线程(授课)也结束了。
    
    在这里,我们假设试卷中有难度较大的问题,当然学生解答较难的问题也会比较花时间。
    在上面的场景中老师除了shutdown方法之外什么也做不了,只能呆呆得等着学生们说,“老师我做完了!”之后才可以有下一步动作。
    这都是因为shutdown方法只是用来通知的方法。
    
    这时如果即使授课时间结束(main线程结束),学校也不能放学(Java进程结束),因为学生们还在解题中呢。这个时候如果你是老师你会怎么做?
    
    一般的情况肯定是经过一定的时间在授课快要结束的时候,如果还有人没有解答出来的话,或者公布给大家解题方法,
    
    或者作为课后习题让学生回去继续思考,然后结束上课对不对!
    
     
    
    定好下课时间后等待结束
    
     
    
    如果经过了一定的时间任务(Runnable)还不结束的时候我们可以通过中止任务(Runnable)的执行,以防止一直等待任务的结束。
    awaitTermination方法正是可以实现这个中止作用的角色。
    
    具体的使用方法是,在shutdown方法调用后,接着调用awaitTermination方法。这时只需要等待awaitTermination方法里第一个参数指定的时间。
    如果在指定的时间内所有的任务都结束的时候,返回true,反之返回false。返回false意味着课程结束的时候还有题目没有解答出来的学生。
    
    通过shutdownNow方法,我们可以作为老师向同学发出“没有解答出来的同学明天给出解答”的命令后结束授课。
    
    shutdownNow方法的作用是向所有执行中的线程发出interrupted以中止线程的运行。这时,各个线程会抛出InterruptedException异常(前提是
    线程中运行了sleep等会抛出异常的方法)


    目前根据该翻译文档,在项目中的代码示例(定时执行的线程池)--

   

private void updateScheduleCallTms(WmsDepartureRegister departureRegister, String vehicle, SysUser sysUser) {
   ScheduledExecutorService scheduledExecutorService = null;
   try {
       scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
       //开启定时线程调用tms
       ScheduledExecutorService finalScheduledExecutorService = scheduledExecutorService;
       scheduledExecutorService.scheduleAtFixedRate(() -> {
           List<WmsCqinboundTms> lastWmsCqinboundTms = getLastWmsCqinboundTms(vehicle);
           if (CollectionUtils.isNotEmpty(lastWmsCqinboundTms)) {
               WmsCqinboundTms tms = lastWmsCqinboundTms.get(0);
               if (!Objects.equals(tms, null) && tms.getTmsInnvocationCount() < CALL_TMS_COUNT) {
                   tms.setId(null);
                   tms.setGmtUpdate(new Date());
                   tms.setGmtCreate(new Date());
                   if (sysUser != null) {
                       tms.setCreateUserName(sysUser.getName());
                       tms.setModifyUserName(sysUser.getName());
                   }
                   tms.setTmsInnvocationCount(tms.getTmsInnvocationCount() + 1);
                   String result = null;
                   try {
                       result = callTms(vehicle, WmsFetchFromTmsTypeEnum.INBOUND.getValue(), WhCodeEnum.UNLCN_XN_CQ.getText());
                   } catch (Exception e) {
                       LOGGER.error("GateControllerServiceImpl.addOutboundOpenByHm error:", e);
                       result = "{\n" +
                               "    \"success\": false,\n" +
                               "    \"records\": null,\n" +
                               "    \"message\": \"调用tms接口超时失败!\"\n" +
                               "}";
                   }
                   if (StringUtils.isNotBlank(result)) {
                       JSONObject jsonObject = JSONObject.parseObject(result);
                       String msg = jsonObject.getString("message");
                       String records = jsonObject.getString("records");
                       Boolean success = jsonObject.getBoolean("success");
                       if (success) {
                           //更新数据为成功
                           tms.setTmsResult(String.valueOf(Boolean.TRUE));
                           List<WmsFecthInboundFromTmsBO> parseArray = JSONArray.parseArray(records, WmsFecthInboundFromTmsBO.class);
                           if (CollectionUtils.isNotEmpty(parseArray)) {
                               insertWmsCqInboundTms(sysUser, parseArray, WmsSysSourceEnum.WMS_CREATE.getValue());
                               departureRegister.setDispatchNo(parseArray.get(0).getShipno());
                               wmsDepartureRegisterMapper.updateByPrimaryKeySelective(departureRegister);
                           }
                       } else {
                           LOGGER.error("GateControllerServiceImpl.addOutboundOpenByHm error", msg);
                           //再调用tms 4次
                           result = "{\n" +
                                   "    \"success\": false,\n" +
                                   "    \"records\": null,\n" +
                                   "    \"message\": \"" + msg + "!\"\n" +
                                   "}";
                           tms.setTmsResult(String.valueOf(Boolean.FALSE));
                       }
                   }
                   wmsCqinboundTmsMapper.insertSelective(tms);
                   //保存对应的日志表
                   insertTmsLogAndTime(vehicle, result);
               } else if (!Objects.equals(tms, null) && tms.getTmsInnvocationCount() >= CALL_TMS_COUNT) {
                   finalScheduledExecutorService.shutdown();
               }
           }
       }, 0, 2, TimeUnit.MINUTES);
   } catch (Exception e) {
       LOGGER.error("WmsCQInboundServiceImple.updateScheduleCallTms 执行失败 error:", e);
   } finally {
       try {
           if (scheduledExecutorService != null) {
               scheduledExecutorService.shutdown();
               if (!scheduledExecutorService.awaitTermination(5, TimeUnit.MINUTES)) {
                   scheduledExecutorService.shutdownNow();
               }
           }
       } catch (InterruptedException e) {
           e.printStackTrace();
       } finally {
           if (scheduledExecutorService != null) {
               scheduledExecutorService.shutdownNow();
           }
       }
   }
}




以上是关于Java 线程池关闭的主要内容,如果未能解决你的问题,请参考以下文章

Java线程池详解

Java线程池详解

Java 线程池详解

newCacheThreadPool()newFixedThreadPool()newScheduledThreadPool()newSingleThreadExecutor()自定义线程池(代码片段

Java线程池详解

Java基础干货如何优雅关闭线程池实践总结