zoukankan      html  css  js  c++  java
  • java中如何优雅的停止一个线程

    前言

    强制停止一个线程是不安全的,线程什么时候可以停止,只有线程自己知道,我们模拟主线程中启动一个工作线程,主线程睡眠3秒后去停止工作线程。

    标志位

    public class ThreadCloseGraceful {
    
      private static class Worker extends Thread {
    
        private volatile boolean running = true;
    
        public Worker(String name) {
          super(name);
        }
    
        @Override
        public void run() {
          String threadName = Thread.currentThread().getName();
          while (running) {
            System.out.println(threadName + " is running");
            try {
              Thread.sleep(1_000);
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          }
          System.out.println(threadName + " exit");
        }
    
        public void shutdown() {
          this.running = false;
        }
      }
    
      public static void main(String[] args) {
        Worker worker = new Worker("Worker");
        worker.start();
        try {
          Thread.sleep(3000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        worker.shutdown();
      }
    }
    

    使用volatile关键字保证内存可见性,主线程修改了,工作线程可以立刻知道running字段的内容变化。如果工作线程已经阻塞了,这种方法没有办法停止,这种情况可以使用线程的interrupt()方法。

    Thread.interrupt()

    public class ThreadCloseGraceful2 {
    
      private static class Worker extends Thread {
    
    
        public Worker(String name) {
          super(name);
        }
    
        @Override
        public void run() {
          String threadName = Thread.currentThread().getName();
          while (true) {
            System.out.println(threadName + " is running");
            try {
              Thread.sleep(10_000);
            } catch (InterruptedException e) {
              e.printStackTrace();
              break;
            }
          }
          System.out.println(threadName + " exit");
        }
      }
    
      public static void main(String[] args) {
        Worker worker = new Worker("Worker");
        worker.start();
        try {
          Thread.sleep(3000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        worker.interrupt();
      }
    }
    

    我们调用interrupt()方法后

    1. 如果工作线程被阻塞了,会抛出InterruptedException异常,我们可以捕获此异常,然后停止线程
    2. 如果工作线程在运行中,会将线程的中断标记设置为true,可以调用isInterrupted()方法,判断当前中断标记是否为true。

    apache工具包中的FileAlterationMonitor文件变化监控器就是通过标志位和中断来实现的。

    强制停止

    public class ThreadService {
    
      private Thread executeThread;
    
      private boolean finished = false;
    
      public void execute(Runnable task) {
        executeThread = new Thread(() -> {
          Thread runner = new Thread(task);
          runner.setDaemon(true);
          runner.start();
          try {
            runner.join();
            finished = true;
          } catch (InterruptedException e) {
            //ignore
          }
        });
        executeThread.start();
      }
    
      public void shutdown(long mills) {
        long currentTime = System.currentTimeMillis();
        while (!finished) {
          if ((System.currentTimeMillis() - currentTime) >= mills) {
            System.out.println("任务超时,需要结束他!");
            executeThread.interrupt();
            break;
          }
          try {
            Thread.sleep(1);
          } catch (InterruptedException e) {
            System.out.println("执行线程被打断!");
            break;
          }
        }
        finished = false;
      }
    }
    

    客户端调用

    public class ThreadCloseForce {
    
    
      public static void main(String[] args) throws InterruptedException {
    
        ThreadService service = new ThreadService();
        long start = System.currentTimeMillis();
        service.execute(() -> {
          //load a very heavy resource.
          /*while (true) {
    
          }*/
          try {
            Thread.sleep(2000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        });
        service.shutdown(3000);
        System.out.println("main start");
        long end = System.currentTimeMillis();
        System.out.println(end - start);
      }
    }
    

    在工作线程内启动一个新的守护线程,当主线程停止工作线程时,会向工作线程发中断信号,就算工作线程在执行一个费时的操作,也会被停止。

    参考

    java多线程正确关闭的方法
    如何优雅的关闭Java线程池
    java 如何优雅的停止一个线程

  • 相关阅读:
    深入理解系统调用
    基于mykernel 2.0编写一个操作系统内核
    如何评测一个软件工程师的计算机网络知识水平与网络编程技能水平?
    如何评测软件工程知识技能水平?
    深入理解TCP的三次握手及其源代码
    Socket与系统调用深度分析
    未来的图书会是什么样子?
    构建调试Linux内核网络代码的环境MenuOS系统
    Python笔记005-神奇的+=
    Python笔记004-元组的拆包和命名元组
  • 原文地址:https://www.cnblogs.com/strongmore/p/14697508.html
Copyright © 2011-2022 走看看