优雅的停止线程

上篇说到public final void stop()函数已过时,那怎么才能优雅的停止线程呢?

在java中又一下三种方式可以停止正在运行的线程

  1. 使用退出标志,使线程正常退出,也就是当润运行完成后线程终止
  2. 使用stop()强制结束 ,这个已经说过已经过时就不再详细说明了
  3. 使用interrupt方法中断线程

设置标志位,结束线程

public class FirstThreadTest extends Thread {
    public boolean flag=true;
    @Override
    public void run()  {
       while (flag){
           try {
               sleep(1000);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }

           System.out.println("运行中。。。" );
       };
        System.out.println("线程即将结束" );
    }

    public static void main(String[] args) {
        FirstThreadTest thread=new FirstThreadTest();
        thread.start();//启动线程 线程处于准备运行阶段
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.flag=false;
    }

}

运行结果:
运行中。。。
运行中。。。
线程即将结束

Process finished with exit code 0
从结果可以看出是停止了,但是这种方式还是问题,看下面代码

public class FirstThreadTest extends Thread {
    public boolean flag=true;
    @Override
    public void run()  {
       while (flag){

       };
        System.out.println("线程即将结束" );
    }

    public static void main(String[] args) {
        FirstThreadTest thread=new FirstThreadTest();
        thread.start();//启动线程 线程处于准备运行阶段
        System.out.println("线程状态1"+ thread.isAlive());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.flag=false;
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程状态2"+ thread.isAlive());
    }

}

运行结果:
线程状态1true
线程状态2true
可以看出线程并没有停止,两次线程状态都是活跃中,并且 “线程即将结束” 没有打印,说明还在循环中,这是为什么呢
造成这种问题的原因是 线程私有栈,与公共栈中的值不同步造成的,解决的方法就是在使用volatile关键字
示例

public class FirstThreadTest extends Thread {
    public volatile boolean flag=true;
    @Override
    public void run()  {
       while (flag){

       };
        System.out.println("线程即将结束" );
    }

    public static void main(String[] args) {
        FirstThreadTest thread=new FirstThreadTest();
        thread.start();//启动线程 线程处于准备运行阶段
        System.out.println("线程状态1"+ thread.isAlive());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.flag=false;
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程状态2"+ thread.isAlive());
    }

}

运行结果
线程状态1true
线程即将结束
线程状态2false

Process finished with exit code 0
可以看出现在线程安全停止了

interrupt 中断线程

相关函数

  • public void interrupt()
    中断这个线程。
    除非当前线程中断自身,这是始终允许的,所以调用此线程的checkAccess方法,这可能会导致抛出SecurityException 。
    如果该线程阻塞的调用wait() , wait(long) ,或wait(long, int)的方法Object类,或者在join() , join(long) , join(long, int) , sleep(long) ,或sleep(long, int) ,这个类的方法,那么它的中断状态将被清除,并且将收到一个InterruptedException 。
  • public static boolean interrupted()
    测试当前线程是否中断。 该方法可以清除线程的中断状态 。 换句话说,如果这个方法被连续调用两次,那么第二个调用将返回false(除非当前线程再次中断,在第一个调用已经清除其中断状态之后,在第二个调用之前已经检查过)。
    忽略线程中断,因为线程在中断时不存在将被该方法返回false所反映
    true如果这个线程已被中断; false否则。
  • public boolean isInterrupted()
    测试这个线程是否被中断。 线程的中断状态不受此方法的影响。
    忽略线程中断,因为线程在中断时不存在将被该方法返回false所反映。
    true如果这个线程已被中断; false否则。

使用示例

public class FirstThreadTest extends Thread {

    @Override
    public void run()  {
      while (true){
         if (isInterrupted()){
             break;
         }
      }
      System.out.println("线程即将结束");
    }

    public static void main(String[] args) {
        FirstThreadTest thread=new FirstThreadTest();
        thread.start();//启动线程 线程处于准备运行阶段
        System.out.println("线程状态1"+ thread.isAlive());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程状态2"+ thread.isAlive());
    }

}

运行结果
线程状态1true
线程即将结束
线程状态2false

Process finished with exit code 0

该方法还有一个问题,从interrupt说明中可以看出 当线程调用wait join sleep阻塞这时会抛售一个异常InterruptedException
那么我们可以捕获这个异常退出该线程

public class FirstThreadTest extends Thread {

    @Override
    public void run()  {
      while (true){
          try {
              sleep(1000);
          } catch (InterruptedException e) {
              e.printStackTrace();
              System.out.println("线程即将结束");
          }
          if (isInterrupted()){
             break;
         }
      }
      System.out.println("线程即将结束");
    }

    public static void main(String[] args) {
        FirstThreadTest thread=new FirstThreadTest();
        thread.start();//启动线程 线程处于准备运行阶段
        System.out.println("线程状态1"+ thread.isAlive());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程状态2"+ thread.isAlive());
    }
}

运行结果1:
线程状态1true
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.jelly.threadtest1.FirstThreadTest.run(FirstThreadTest.java:12)
线程即将结束
线程状态2true
运行结果2:
线程状态1true
线程即将结束
线程状态2true
注意:只有线程进入sleep wait join状态时调用interrupt才会抛出该异常,如果当前线程有调用阻塞,但是现在没有在该状态下则不会抛出异常
如上面例子:不一定每次都会抛出该异常

posted @ 2020-08-09 10:51  jelly_wt  阅读(123)  评论(0编辑  收藏  举报