美文网首页
一种强制关闭线程的方法

一种强制关闭线程的方法

作者: herohua | 来源:发表于2020-01-12 12:40 被阅读0次

在Java中,停止一个线程的主要机制是中断,中断并不是强迫终止一个线程,它是一种协作机制,是给线程传递一个取消信号,但是由线程来决定如何及何时退出。
Thread的stop()方法是一个强制关闭线程的方法,但是现在jdk版本已不再推荐使用。


过时的stop()方法.png

1. JDK对线程中断的支持

jdk中断机制主要涉及三个方法,分别是:


interrupt()方法.png
interrupted()方法.png
isInterrupted()方法.png
  1. interrupt()方法是一个实例方法,该方法用于设置当前线程对象的中断标识位。


    interrupt()方法源码.png
  2. interrupted()方法用于判断当前线程是否被中断,并且该方法调用结束的时候会清空中断标识位。


    interrupted()方法会清空中断标识位.png
  3. isInterrupted是一个实例方法,主要用于判断当前线程对象的中断标志位是否被标记了,如果被标记了则返回true表示当前已经被中断,否则返回false。


    isInterrupted()方法不会清空中断标识位.png

2. interrupt()方法详解

先来看一下官方文档的描述:

interrupt()方法官方描述.png
简单概括起来就是:只有当线程处于阻塞状态时(包括调用wait()、sleep()、join方法时),能够捕获到[InterruptedException],中断标识位将被清空。如果不是处于阻塞状态,即使线程被打断,线程仍会继续执行,因为只是改变了状态标识位,线程无法获得打断信号。
public class ThreadInterupt {

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            while (true) {
                // 即使被中断也会继续执行
            }
        });

        t1.start();
        System.out.println(t1.isInterrupted());
        // 中断线程
        t1.interrupt();
        System.out.println(t1.isInterrupted());
    }
}
public class ThreadInterupt {

    public static void main(String[] args) {
        Object MONITOR = new Object();

        Thread t1 = new Thread(() -> {
            while (true) {

                try {
                    // 1. Thread.sleep(1000);

                    // 2. wait()
                    synchronized (MONITOR) {
                        MONITOR.wait(10);
                    }

                } catch (InterruptedException e) {
                    System.out.println("收到打断信号");
                    System.out.println("线程" + Thread.interrupted());
                    e.printStackTrace();
                }
            }
        });

        t1.start();
        System.out.println(t1.isInterrupted());
        // 中断线程
        t1.interrupt();
        System.out.println(t1.isInterrupted());
    }
}

3. 采用优雅的方式结束线程的生命周期

3.1 通过开关判断是否关闭线程

public class ThreadCloseGraceful {

    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) {
        Worker worker = new Worker();
        worker.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 关闭线程
        worker.shutdown();
    }
}

3.2 通过Thread.interrupted()静态方法判断是否while循环

public class ThreadCloseGraceful2 {

    static class Worker extends Thread {

        @Override
        public void run() {
            while (true) {
                // 如果线程被打断,退出while循环,执行其它代码
                if (Thread.interrupted())
                    break;
            }

            // 执行其它代码...
        }
    }

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

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        worker.interrupt();
    }
}

以上两种方式都是采取while循环+变量判断的方式决定线程是否继续执行,但是存在一个问题,假入代码在while循环中blocked,可能是网络原因,可能是加载一个大的资源,总之被hang住了,那么下一次变量判断没有执行的机会,那么线程就不能关闭。所以还是需要一个强制关闭线程的方法,stop()方法已经过时,不推荐使用。

public class ThreadCloseGraceful2 {

    static class Worker extends Thread {

        @Override
        public void run() {
            while (true) {

                // load a heavy resource,hang...
                // if statement mo chance to execute

                // 如果线程被打断,退出while循环,执行其它代码
                if (Thread.interrupted())
                    break;
            }

            // 执行其它代码...
        }
    }

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

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        worker.interrupt();
    }
}

4. 强制关闭线程的解决方案

我们都知道创建守护线程的线程结束生命周期,那么守护线程也结束自己的生命周期,利用这一特性,可以设计以下方案。
利用一个类包装执行线程的方法和关闭线程的方法:

public class ThreadService {

    // 执行线程
    private Thread executeThread;

    // 执行线程是否执行完毕标记
    private boolean finished = false;

    public void execute(Runnable target) {
        executeThread = new Thread() {
            @Override
            public void run() {
                // 任务交给一个守护线程运行
                Thread runner = new Thread(target);
                runner.setDaemon(true);

                runner.start();

                try {
                    runner.join();  // 执行线程executeThread在此阻塞,等待守护线程消亡
                    finished = true;
                } catch (InterruptedException e) {

                }

            }
        };

        executeThread.start();
    }

    public void shutdown(long mills) {
        long currentTime = System.currentTimeMillis();
        while (!finished) {
            if ((System.currentTimeMillis() - currentTime) >= mills) {
                System.out.println("任务超时,需要结束");
                // 这里打断执行线程,执行线程catch到InterruptedException,不再阻塞
                // 执行线程消亡,守护线程随着执行线程一块消亡
                // 从而达到强制关闭线程的目的
                // Java Api没有强制关闭线程的方法,有一个Thread.stop()方法已经过时
                executeThread.interrupt();
                break;
            }

            try {
                executeThread.sleep(1);
            } catch (InterruptedException e) {
                System.out.println("执行线程被打断");
                break;
            }
        }

        finished = false;
    }
}

主线程调用执行线程和关闭线程的方法:

public class ThreadStopFoece {

    public static void main(String[] args) {

        ThreadService service = new ThreadService();
        long startTime = System.currentTimeMillis();
        service.execute(() -> {
            // 用一个线程执行任务,某种原因使得线程hang住了,无法退出,需要手动关闭
            while (true) {

            }
        });
        // 手动关闭,指定关闭前运行时间
        service.shutdown(10000);
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime);
    }
}

这个方案使用到了几个知识点:

  1. 守护线程随着父线程的消亡而消亡;
  2. join方法: Waits for this thread to die.这里守护线程join执行线程,导致执行线程阻塞,等待守护线程执行完毕;
  3. 调用join方法可以捕获到InterruptedException ,shutdown方法里interrupt执行线程,执行线程中断,从而守护线程也结束。

相关文章

  • 一种强制关闭线程的方法

    在Java中,停止一个线程的主要机制是中断,中断并不是强迫终止一个线程,它是一种协作机制,是给线程传递一个取消信号...

  • Java关闭线程的安全方法

    Java之前有一个api方法可以直接关闭线程,stop(),由于这个方法是强制性地关闭线程,有的时候会发生错误,之...

  • Java线程池的关闭

    一 java线程池关闭方法 1.1 shutdown void shutdown() 此方法关闭线程池不是直接关闭...

  • 强制关闭占用端口的线程

    查看端口使用线程netstat -ano |findStr 端口号 关闭线程taskkill /pid 线程号 /f

  • 多线程之中断线程

    1、 java中没有可以强制线程终止的方法。但是存在interrupt方法用来请求终止线程。当对一个线程调用int...

  • 停止线程池的正确方法

    shutdown()方法仅仅是关闭线程池的队列入口 1、shutdown()代表关闭线程池队列入口,那么isShu...

  • redis4远程和本地登录配置

    1.强制关闭: (1)方法1:./redis-cli shutdown (2)方法2:kill -xxx PID...

  • Java中断

    关闭线程 Java 中如何关闭一个线程,已经废弃的方法Thread.stop()会造成不可预知的bug,官方说明 ...

  • 利用钩子优雅关停kafka

    背景 利用kafka进行消息生产和消费,生产线程或消费线程在tomcat关闭的时候无法优雅的停止,一定要强制退出才...

  • Java锁

    Thread几个方法 a、start()方法,调用该方法开始执行该线程;b、stop()方法,调用该方法强制结束该...

网友评论

      本文标题:一种强制关闭线程的方法

      本文链接:https://www.haomeiwen.com/subject/nhgbactx.html