当前位置 主页 > 网站技术 > 代码类 >

    面试题:Java中如何停止线程的方法

    栏目:代码类 时间:2019-09-11 18:03

    如何停止线程是Java并发面试中的常见问题,本篇文章将从答题思路到答题细节给出一些参考。

    答题思路:

    停止线程的正确方式是使用中断 想停止线程需要停止方,被停止方,被停止方的子方法相互配合 扩展到常见的错误停止线程方法:已被废弃的stop/suspend,无法唤醒阻塞线程的volatile

    1. 正确方式是中断

    其实从逻辑上也很好理解的,一个线程正在运行,如何让他停止?

    A. 从外部直接调用该线程的stop方法,直接把线程停下来。

    B. 从外部通过中断通知线程停止,然后切换到被停止的线程,该线程执行一系列逻辑后自己停止。

    很明显B方法要比A方法好很多,A方法太暴力了,你根本不知道被停止的线程在执行什么任务就直接把他停止了,程序容易出问题;而B方法把线程停止交给线程本身去做,被停止的线程可以在自己的代码中进行一些现场保护或者打印错误日志等方法再停止,更加合理,程序也更具健壮性。

    下面要讲的是线程如何能够响应中断,第一个方法是通过循环不断判断自身是否产生了中断:

    public class Demo1 implements Runnable{  @Override  public void run() {    int num = 0;    while(num <= Integer.MAX_VALUE / 2 && !Thread.currentThread().isInterrupted()){      if(num % 10000 == 0){        System.out.println(num);      }      num++;    }  }  public static void main(String[] args) throws InterruptedException {    Thread thread = new Thread(new Demo1());    thread.start();    thread.sleep(1000);    thread.interrupt();  }}

    在上面的代码中,我们在循环条件中不断判断线程本身是否产生了中断,如果产生了中断就不再打印

    还有一个方法是通过java内定的机制响应中断:当线程调用sleep(),wait()方法后进入阻塞后,如果线程在阻塞的过程中被中断了,那么线程会捕获或抛出一个中断异常,我们可以根据这个中断异常去控制线程的停止。具体代码如下:

    public class Demo3 implements Runnable {  @Override  public void run() {    int num = 0;    try {      while(num < Integer.MAX_VALUE / 2){        if(num % 100 == 0){          System.out.println(num);        }        num++;        Thread.sleep(10);      }    } catch (InterruptedException e) {//捕获中断异常,在本代码中,出现中断异常后将退出循环      e.printStackTrace();    }  }  public static void main(String[] args) throws InterruptedException {    Thread thread = new Thread(new Demo3());    thread.start();    Thread.sleep(5000);    thread.interrupt();  }}

    2. 各方配合才能完美停止

    在上面的两段代码中已经可以看到,想通过中断停止线程是个需要多方配合。上面已经演示了中断方和被中断方的配合,下面考虑更多的情况:假如要被停止的线程正在执行某个子方法,这个时候该如何处理中断?

    有两个办法:第一个是把中断传递给父方法,第二个是重新设置当前线程为中断。

    先说第一个例子:在子方法中把中断异常上抛给父方法,然后在父方法中处理中断:

    public class Demo4 implements Runnable{  @Override  public void run() {    try{//在父方法中捕获中断异常      while(true){        System.out.println("go");        throwInterrupt();      }    }catch (InterruptedException e) {      e.printStackTrace();      System.out.println("检测到中断,保存错误日志");    }  }  private void throwInterrupt() throws InterruptedException {//把中断上传给父方法    Thread.sleep(2000);  }  public static void main(String[] args) throws InterruptedException {    Thread thread = new Thread(new Demo4());    thread.start();    Thread.sleep(1000);    thread.interrupt();  }}