美文网首页
Java停止线程的几种方式

Java停止线程的几种方式

作者: Bfmall | 来源:发表于2023-04-16 17:24 被阅读0次

    1、正常运行结束

    所谓正常运行结束,我的理解就是程序正常运行结束,线程自动结束。

    2. 使用退出标志退出线程

    一般run()方法执行完,线程就会正常结束,然而腻,常常有些线程是伺服线程。他们需要长时间的运行,只有在外部某些条件满足的情况下,才能关闭这些线程。使用一个变量来控制循环,例如:最直接的方法就是设一个boolean类型的标志,并通过设置这个标志位true或false来控制while循环是否退出,下面放代码:

    private class ThreadE extends Thread {
            private volatile  boolean isRunning = true;
    
            public void setRunning(boolean isRunning) {
                this.isRunning = isRunning;
            }
    
            @Override
            public void run() {
                super.run();
                int i=0;
                while(isRunning) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    i ++;
                    Log.i(TAG, "ThreadE==>i="+i);
                }
            }
        }
    
        private void testThread() {
            ThreadE threadE = new ThreadE();
            threadE.start();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //加入变量可以正常停止线程
            threadE.setRunning(false);
        }
    

    这里定义了一个是否正在运行的标志isRunning,当isRunning为true时(默认为true),线程正在运行,当isRunning为false时,while循环退出。在定义isRunning时使用了一个Java关键字volatile,这个关键字的目的是使isRunning同步,也就是说在同一时刻只能由一个线程来修改isRunning的值。

    输出结果:

    ThreadE==>i=1
    ThreadE==>i=2
    ThreadE==>i=3
    ThreadE==>i=4
    ThreadE==>i=5
    ThreadE==>i=6
    ThreadE==>i=7
    ThreadE==>i=8
    ThreadE==>i=9
    ThreadE==>i=10
    ThreadE==>thread run end
    

    可见线程正常退出了。

    3.Interrupt方法结束线程

    (3.1)首先看一个调用intterrupt方法中断不了的例子:

        private class ThreadF extends Thread {
    
            @Override
            public void run() {
                super.run();
                int i=0;
                while(!isInterrupted()) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        //此处捕捉异常之后,不做任何操作
                    }
                    i ++;
                    Log.i(TAG, "ThreadF==>i="+i+", isInterrupted="+isInterrupted());
                }
                Log.d(TAG, "ThreadF==>thread end...isInterrupted="+isInterrupted());
            }
        }
    
        private void testThread05() {
            ThreadF threadF = new ThreadF();
            threadF.start();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            threadF.interrupt();
    
            //或者调用stop中断异常
            /**try {
                //调用stop会抛出异常Caused by: java.lang.UnsupportedOperationException,
                //加上try...catch即可
                threadD.stop();
            } catch (Exception e) {
                e.printStackTrace();
            }**/
        }
    

    输出如下:

    ThreadF==>i=1, isInterrupted=false
    ThreadF==>i=2, isInterrupted=false
    ThreadF==>i=3, isInterrupted=false
    ThreadF==>i=4, isInterrupted=false
    ThreadF==>i=5, isInterrupted=false
    ThreadF==>i=6, isInterrupted=false
    ThreadF==>i=7, isInterrupted=false
    ThreadF==>i=8, isInterrupted=false
    ThreadF==>i=9, isInterrupted=false
    
    ......
    
    ThreadF==>i=200, isInterrupted=false
    ThreadF==>i=201, isInterrupted=false
    ......
    
    

    此时调用interrrupt或stop方法无法结束线程,

    看下面两种方法的解决方案:

    (3.2)方法一:

    线程处于阻塞状态:如使用了sleep,同步锁的wait(),socket中的receiver(),accept()等方法时,会使线程处于阻塞状态。当调用线程interrupt()方法时,会抛出InterruptException异常。阻塞中的那个方法抛出这个异常,通过代码可以捕获该异常,然后跳出循环状态,从而让我们有机会结束这个线程的执行。通常有些小伙伴认为只要调用interrupt方法,线程就会结束,实际上是不正确的,一定要先捕获InterruptException异常之后通过break来跳出循环,才能正常结束run()方法。

    private class ThreadF extends Thread {
    
            @Override
            public void run() {
                super.run();
                int i=0;
                while(!isInterrupted()) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        //当线程调用interrupt中断线程时,此处捕捉到异常,并通过break跳出循环也可以结束线程
                        Log.i(TAG, "catch execption...break while loop...");
                        break;
                    }
                    i ++;
                    Log.i(TAG, "ThreadF==>i="+i+", isInterrupted="+isInterrupted());
                }
                Log.d(TAG, "ThreadF==>thread end...isInterrupted="+isInterrupted());
            }
        }
    
        private void testThread05() {
            ThreadF threadF = new ThreadF();
            threadF.start();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //调用interrupt中断线程
            threadF.interrupt();
        }
    

    输出结果:

    ThreadF==>i=1, isInterrupted=false
    ThreadF==>i=2, isInterrupted=false
    ThreadF==>i=3, isInterrupted=false
    ThreadF==>i=4, isInterrupted=false
    ThreadF==>i=5, isInterrupted=false
    ThreadF==>i=6, isInterrupted=false
    ThreadF==>i=7, isInterrupted=false
    ThreadF==>i=8, isInterrupted=false
    ThreadF==>i=9, isInterrupted=false
    catch execption...break while loop...
    ThreadF==>thread end...isInterrupted=false //可见跳出循环之后,isInterrupted依然为false
    

    线程结束。

    (3.3)方法二:

    和方式一很相似,也是通过捕捉InterruptedException异常来结束线程,只不过在捕获异常之后,再次调用interrupt()方法来结束的,对方式一代码更改如下:

    private class ThreadF extends Thread {
    
            @Override
            public void run() {
                super.run();
                int i=0;
                while(!isInterrupted()) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        //当主动调用interrupt时,就能捕捉中断异常,再次调用interrupt即可中断
                        interrupt();
                        Log.i(TAG, "catch exception...isInterrupted="+isInterrupted());
                    }
                    i ++;
                    Log.i(TAG, "ThreadF==>i="+i+", isInterrupted="+isInterrupted());
                }
                Log.d(TAG, "ThreadF==>thread end...isInterrupted="+isInterrupted());
            }
        }
    
        private void testThread05() {
            ThreadF threadF = new ThreadF();
            threadF.start();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            threadF.interrupt();
        }
    

    输出结果:

    ThreadF==>i=1, isInterrupted=false
    ThreadF==>i=2, isInterrupted=false
    ThreadF==>i=3, isInterrupted=false
    ThreadF==>i=4, isInterrupted=false
    ThreadF==>i=5, isInterrupted=false
    ThreadF==>i=6, isInterrupted=false
    ThreadF==>i=7, isInterrupted=false
    ThreadF==>i=8, isInterrupted=false
    ThreadF==>i=9, isInterrupted=false
    catch execption...break while loop...
    ThreadF==>i=10, isInterrupted=true
    ThreadF==>thread end...isInterrupted=true//再次调用interrupt()方法之后,isInterrupted为true了
    

    4.stop()方法终止线程(不安全)

    这个各位小伙伴应该在学习中都有用过吧,我们可以直接使用thread.stop()来强行终止线程,但是stop()方法是很危险的,就想突然关闭电源一样。这样子可能机会产生不可预料的结果,不安全主要是:

    thread.stop()调用之后,创建子线程的线程就会抛出ThreadDeatherror的错误,并且会释放子线程所持有的所有锁。一般任何进行加锁的代码块,都是为了保护数据的一致性,如果在调用thread.stop()后导致了该线程所持有的所有的锁突然释放,那么被保护的数据就可能呈现不一致性,其他线程在使用这些被破坏的数据时,有可能导致一些很奇怪的应用程序错误。因此,并不推荐使用stop()方法来终止线程。

    ————————————————

    参考:
    https://blog.csdn.net/weixin_44118963/article/details/119721513
    https://segmentfault.com/a/1190000039696074?sort=newest

    相关文章

      网友评论

          本文标题:Java停止线程的几种方式

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