zoukankan      html  css  js  c++  java
  • 唯品会开发手册-并发处理

    Rule 4.

    【强制】正确停止线程

    Thread.stop()不推荐使用,强行的退出太不安全,会导致逻辑不完整,操作不原子,已被定义成Deprecate方法。

    停止单条线程,执行Thread.interrupt()。

    停止线程池:

    • ExecutorService.shutdown(): 不允许提交新任务,等待当前任务及队列中的任务全部执行完毕后退出

    • ExecutorService.shutdownNow(): 通过Thread.interrupt()试图停止所有正在执行的线程,并不再处理还在队列中等待的任务

    最优雅的退出方式是先执行shutdown(),再执行shutdownNow(),vjkit的ThreadPoolUtil进行了封装。

     //当任务一直没处理完成 超过规定时间后 强制关闭线程、退出

    if(!executorService.awaitTermination(10, TimeUnit.SECONDS)){
    executorService.shutdownNow();
    }

    Rule 5. 【强制】编写可停止的Runnable

    执行Thread.interrupt()时,如果线程处于sleep(), wait(), join(), lock.lockInterruptibly()等blocking状态,会抛出InterruptedException,如果线程未处于上述状态,则将线程状态设为interrupted。

    因此,如下的代码无法中断线程:

    public void run() {
    
      while (true) { //WRONG,无判断线程状态。
        sleep();
      }
    
      public void sleep() {
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          logger.warn("Interrupted!", e); //WRONG,吃掉了异常,interrupt状态未再传递
        }
      }
    }

    5.1 正确处理InterruptException

    因为InterruptException异常是个必须处理的Checked Exception,所以run()所调用的子函数很容易吃掉异常并简单的处理成打印日志,但这等于停止了中断的传递,外层函数将收不到中断请求,继续原有循环或进入下一个堵塞。

    正确处理是调用Thread.currentThread().interrupt(); 将中断往外传递

    //RIGHT
    public void myMethod() {
      try {
        ...
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
      }
    }

    5.2 主循环及进入阻塞状态前要判断线程状态

    //RIGHT
    public void run() {
      try {
        while (!Thread.isInterrupted()) {
          // do stuff
        }
      } catch (InterruptedException e) {
        logger.warn("Interrupted!", e);
      }
    }

    其他如Thread.sleep()的代码,在正式sleep前也会判断线程状态。

     

    Rule 6. 【强制】Runnable中必须捕获一切异常

    如果Runnable中没有捕获RuntimeException而向外抛出,会发生下列情况:

    1) ScheduledExecutorService执行定时任务,任务会被中断,该任务将不再定时调度,但线程池里的线程还能用于其他任务。

    2) ExecutorService执行任务,当前线程会中断,线程池需要创建新的线程来响应后续任务

    3) 如果没有在ThreadFactory设置自定义的UncaughtExceptionHanlder,则异常最终只打印在System.err,而不会打印在项目的日志中

    因此建议自写的Runnable都要保证捕获异常; 如果是第三方的Runnable,可以将其再包裹一层vjkit中的SafeRunnable。

    executor.execute(ThreadPoolUtil.safeRunner(runner));


    待续...
     
  • 相关阅读:
    设计模式-外观模式
    发生死锁怎么办
    设计模式-工厂模式
    设计模式-模板方法
    设计模式-命令模式(Command)
    设计模式-单例模式
    设计模式-装饰器模式
    CQRS之旅——旅程8(后记:经验教训)
    CQRS之旅——旅程7(增加弹性和优化性能)
    CQRS之旅——旅程6(我们系统的版本管理)
  • 原文地址:https://www.cnblogs.com/zhangfengshi/p/9259367.html
Copyright © 2011-2022 走看看