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 如何优雅的停止一个线程

  • 相关阅读:
    java 数组及数组得内存管理总结
    js 日期格式化
    url获取参数值,支持中文、英文
    C# log4net 的日志代码配置
    js 处理浏览器显示地址
    mui <a>标签跳转失效的处理
    js 实时输入事件
    asp.mvc 页面获取当前请求的控制器和方法
    js 获取元素值
    DllImport System.DllNotFoundException 找不到指定的模块。 (Exception from HRESULT: 0x8007007E)
  • 原文地址:https://www.cnblogs.com/strongmore/p/14697508.html
Copyright © 2011-2022 走看看