Thread中断Interrupt方法学习&采用优雅的方式结束线程生命周期

Thread中断Interrupt方法学习&采用优雅的方式结束线程生命周期

在jdk中关于interrupt相关方法有三个:

简单来使用一下interrupt:

/**
 * @program: ThreadDemo
 * @description: 线程中断
 * @author: hs96.cn@Gmail.com
 * @create: 2020-09-03
 */
public class ThreadInterrupt {
    public static void main(String[] args) {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                while (true) {
                }
            }
        };
        t1.start();

        // start之后处于runnable,并不一定马上就会running。所以设置短暂休眠等待t1启动
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(t1.isInterrupted());
        t1.interrupt();
        System.out.println(t1.isInterrupted());
    }
}

运行效果如下:

可以看到:没有中断的线程中断了,但是程序却没有结束。interrupt()不能中断在运行中的线程,它只能改变中断状态而已。

找到interrupt()方法的文档:

可以看到如果线程中调用wait,join,sleep会捕获InterruptedException:

我们先用sleep()方法试一下,代码如下:

/**
 * @program: ThreadDemo
 * @description: 线程中断
 * @author: hs96.cn@Gmail.com
 * @create: 2020-09-03
 */
public class ThreadInterrupt {
    public static void main(String[] args) {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(3_1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t1.start();

        // start之后处于runnable,并不一定马上就会running。所以设置短暂休眠等待t1启动
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(t1.isInterrupted());
        t1.interrupt();
        System.out.println(t1.isInterrupted());
    }
}

再试一下wait()方法:

/**
 * @program: ThreadDemo
 * @description: 线程中断
 * @author: hs96.cn@Gmail.com
 * @create: 2020-09-03
 */
public class ThreadInterrupt {
    private static final Object MONITOR = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                while (true) {
                    synchronized (MONITOR) {
                        try {
                            MONITOR.wait(1_000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        };
        t1.start();

        // start之后处于runnable,并不一定马上就会running。所以设置短暂休眠等待t1启动
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(t1.isInterrupted());
        t1.interrupt();
        System.out.println(t1.isInterrupted());
    }
}

运行效果如下:

再试一下join():

/**
 * @program: ThreadDemo
 * @description: join中断线程
 * @author: hs96.cn@Gmail.com
 * @create: 2020-09-03
 */
public class ThreadInterrupt {
    private static final Object MONITOR = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            while (true) {

            }
        }, "t1");
        t1.start();


        Thread t2 = new Thread(() -> {
            try {
                Thread.sleep(100);
                t1.interrupt();
                System.out.println("interrupt t1 thread");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t2.start();

        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行效果如下:

线程t1被中断了,但是为什么没收到中断异常呢?

其实join()的是main线程,而我们打断的是t1线程,主线程的join()不会收到中断异常,所以代码改造如下:

/**
 * @program: ThreadDemo
 * @description: join中断线程
 * @author: hs96.cn@Gmail.com
 * @create: 2020-09-03
 */
public class ThreadInterrupt {
    private static final Object MONITOR = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            while (true) {

            }
        }, "t1");
        t1.start();

        Thread main = Thread.currentThread();
        Thread t2 = new Thread(() -> {
            try {
                Thread.sleep(100);
                main.interrupt();
                System.out.println("interrupt t1 thread");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t2.start();

        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行效果如下:

同样也捕获到了中断异常,但都没有让t线程退出,我们来看一下join的源码:

其实join里也是用到了wait()方法的。

那么怎么能让t1线程退出呢,这里有个简单粗暴的方法,但是官方并不推荐,就是stop()方法:

我们在代码的结尾加上

 t1.stop();

运行效果如下:

已经实现了我们想要的效果,但是并不推荐这么用,那么到底该怎么优雅的中断线程呢?

用一个标记来控制

/**
 * @program: ThreadDemo
 * @description: 优雅地停止线程 Graceful thread stop 1. 使用开关变量控制是否启动
 * @author: hs96.cn@Gmail.com
 * @create: 2020-09-03
 */
public class ThreadCloseGraceful {
    private static class Worker extends Thread {
        private volatile boolean start = true;

        @Override
        public void run() {
            while (start) {
                // ...
            }
        }

        public void shutdown() {
            this.start = false;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Worker worker = new Worker();
        worker.start();

        Thread.sleep(2_000);

        worker.shutdown();
    }
}

运行效果如下:

利用打断机制

/**
 * @program: ThreadDemo
 * @description: 优雅地停止线程 Graceful thread stop 通过打断的方式实现
 * @author: hs96.cn@Gmail.com
 * @create: 2020-09-03
 */
public class ThreadCloseGraceful2 {
    private static class Worker extends Thread {
        @Override
        public void run() {
            while (true) {
                // 1. sleep()
                /*try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    break;// return;
                }*/

                // 2. if
                if (Thread.interrupted()) {
                    break;// return;
                }
            }
            // ... catch中使用break;可以在while()后执行其他操作
            System.out.println("break-opera after while");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Worker worker = new Worker();
        worker.start();

        Thread.sleep(3_000);

        worker.interrupt();
    }
}

运行效果如下:

上面两个方法确实可以中断线程,但是有这样一个问题改如何解决呢?

也就是除了第一次判断了一下interrupted,后面就被阻塞了,那么改如何解决呢?这个我们后续再学习。

posted @ 2020-09-03 23:05  风暴松鼠  阅读(256)  评论(0)    收藏  举报