使用stop方法调用stop方法会直接停止正在运行的线程,可能会导致一些清理工作无法完成。并且stop已被标记为过时的方法,不推荐使用。正确的使用姿势是使用两阶段终止模式,即一个线程发送终止指令,另一个线程接收指令,决定何时停止。使用旗帜publicvoidstop(){stopFlag=true;}}"在stopFlag中加入volatile是为了保证可见性,本例中我使用while循环不断判断,如果项目中不用while,可以在key判断nodes,然后退出run方法。可以使用interrupt方法。如果我们的任务中有阻塞逻辑,比如调用Thread.sleep方法,如何停止线程呢?从线程状态转换图中找答案。从图中可以看出,如果想让线程进入终止状态,前提是线程在运行,当我们要终止一个线程的时候,如果此时线程处于阻塞状态,我们该如何将它切换到运行状态?我们可以通过调用Thread#interrupt将阻塞状态的线程切换到就绪状态方法,并输入operation系统预定运行,然后终止。线程在运行状态调用中??断方法会发生什么?publicclassRunTaskCase1{privateThreadtaskThread;publicvoidstart(){taskThread=newThread(()->{while(true){System.out.println("doSomething");}});taskThread.start();}publicvoidstop(){taskThread.interrupt();}}依次调用start方法和stop方法,发现线程还没有停止。“实际上,当线程处于运行状态时,interrupt方法只是在当前线程上标记了一个停止,停止的逻辑需要我们自己去实现。”“Thread类提供了以下两种方法来判断线程是否被中断。”isInterruptedinterrupted这两个方法虽然可以判断状态,但是还是有细微差别的(100);thread.interrupt();//trueSystem.out.println(thread.isInterrupted());//trueSystem.out.println(thread.isInterrupted());//trueSystem.out.println(thread.isInterrupted());}@TestpublicvoidtestInterrupt2(){Thread.currentThread().interrupt();//trueSystem.out.println(Thread.interrupted());//falseSystem.out.println(Thread.interrupted());//falseSystem.out.println(Thread.interrupted());}《isInterrupted和interrupted的区别如下》Thread#isInterrupted:测试线程是否被中断,执行完Thread不会改变状态标志#interrupted:测试线程是否为中断状态。执行完后,将中断标志改为false“所以此时我们不需要定义自己的状态,直接使用中断标志即可。之前的代码可以改成下面这样”publicclassRunTaskCase2{privateThreadtaskThread;publicvoidstart(){taskThread=newThread(()->{while(!Thread.currentThread().isInterrupted()){System.out.println("doSomething");}});taskThread.start();}publicvoidstop(){taskThread.interrupt();}}线程阻塞时,调用中断方法,将抛出InterruptedException,也可以终止线程的执行。线程被阻塞:抛出异常退出.sleep(100);}catch(InterruptedExceptione){e.printStackTrace();}}});taskThread.start();}publicvoidstop(){stopFlag=true;taskThread.interrupt();}}当然还有总可以用中断标志退出,《注意,异常发生时需要重新设置中断标志位》。publicclassRunTaskCase4{privateThreadtaskThread;publicvoidstart(){taskThread=newThread(()->{while(!Thread.currentThread().isInterrupted()){try{System.out.println("doSomething");TimeUnit.MICROSECONDS.sleep(100);}catch(InterruptedExceptione){//重置中断标志为trueThread.currentThread().interrupt();e.printStackTrace();}}});taskThread.start();}publicvoidstop(){taskThread.interrupt();}}最后想问大家一个问题?RunTaskCase3和RunTaskCase4哪个实现方式更好?”虽然RunTaskCase4的代码看起来更简洁,但是不推荐使用RunTaskCase4,因为如果在run方法库中调用了第三方类,出现了InterruptedException,但是没有重置中断标志,会导致线程永远运行,出于同样的原因,不推荐使用RunTaskCase2。”本文转载自微信公众号“Java知堂”,可通过以下二维码关注,转载请联系Java知堂公众号。
