signed

QiShunwang

“诚信为本、客户至上”

多线程系列学习:线程终止

2021/3/21 0:57:25   来源:

今天聊一下线程的终止,目前知道的是两种方式:

  1. 通过标志变量终止
  2. 通过中断标记终止

 

一、通过标志变量终止

 通过标志变量,可以终止正在运行的线程,测试代码如下:

    // 通过标记变量,退出正在运行的线程
    static class Demo extends Thread{
        // volatile修饰,保证每次读取的都是变量的最新值
        private volatile boolean runFlag = true;

        @Override
        public void run() {
            try {
                int i = 0;
                while (runFlag){
                    System.out.println("demo线程  getState() =  "+getState()+" and i = "+i);
                    i++;
                    Thread.sleep(100);
                }
            }catch (InterruptedException e){
                System.out.println("demo线程 抛出InterruptedException异常, getState() =  "+getState());
                System.out.println("demo线程 抛出InterruptedException异常, isInterrupted() =  "+isInterrupted());
            }
            System.out.println("demo线程 :运行结束, runFlag =  "+ runFlag);
        }

        // 停止线程
        public void stopThread(){
            this.runFlag = false;
            System.out.println("main线程 :设置 runFlag =  "+ runFlag);
        }
    }
      public static void main(String[] args) {
        // 1. 通过标记变量,停止正在运行的线程
        Demo demo = new Demo();
        demo.start();
        System.out.println("demo线程  getState() =  "+demo.getState());
        // 主线程休眠50ms,让出cup给demo线程
        try {
            System.out.println("main线程  getState() =  "+Thread.currentThread().getState());
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        demo.stopThread();

    }

测试结果如下:

demo线程  getState() =  RUNNABLE
main线程  getState() =  RUNNABLE
demo线程  getState() =  RUNNABLE and i = 0
demo线程  getState() =  RUNNABLE and i = 1
demo线程  getState() =  RUNNABLE and i = 2
demo线程  getState() =  RUNNABLE and i = 3
demo线程  getState() =  RUNNABLE and i = 4
main线程 :设置 runFlag =  false
demo线程 :运行结束, runFlag =  false

原理也比较容易理解,就是通过循环判断标志变量,来决定是否继续执行。

 

二、通过中断标记终止

 主要是调用了interrupt方法,来设置线程的中断标记,然后循环判断中断标记来决定是否继续执行,测试代码:

    // 通过中断标志,中断处于阻塞或运行的线程
    static class Demo2 extends Thread{
        @Override
        public void run() {
            try {
                while (!isInterrupted()){
                    for (int i = 0; i < 10; i++) {
                        System.out.println(Thread.currentThread().getName()+":正在运行,i = "+i);
                        if (i >= 5){
                            Thread.sleep(1000);
//                            synchronized (this){
//                                wait();
//                            }
                        }
                    }
                }
            }catch (Exception e){
                System.out.println("异常终止:");
                e.printStackTrace();
            }
            System.out.println("demo2线程 :运行结束, getState() =  "+ getState());
        }
    }
    public static void main(String[] args) {
        // 2. 通过中断标志,终止线程
        Demo2 demo2 = new Demo2();
        demo2.start();
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        demo2.interrupt();

    }

测试结果:

Thread-0:正在运行,i = 0
Thread-0:正在运行,i = 1
Thread-0:正在运行,i = 2
Thread-0:正在运行,i = 3
Thread-0:正在运行,i = 4
Thread-0:正在运行,i = 5
异常终止:
java.lang.InterruptedException: sleep interrupted
demo2线程 :运行结束, getState() =  RUNNABLE
	at java.lang.Thread.sleep(Native Method)
	at com.thread.stop.StopThread$Demo2.run(StopThread.java:75)

调用线程的interupt方法,可以设置中断标记为true,但是,如果线程处于阻塞状态,那么就会抛出java.lang.InterruptedException异常,并且会将中断标记重置为false

 判断线程是否出于中断状态,除了isInterrupted方法,还有interrupted方法,两者的区别在于:interrupted会重置中断标记为false,换句话说,对于中断的线程,第一此返回的true,那么第二次返回的就是false