美文网首页
Java基础-停止Thread

Java基础-停止Thread

作者: 杨0612 | 来源:发表于2020-08-27 11:13 被阅读0次
API 停止线程的方法
public final synchronized void stop(Throwable obj) ;
public final void stop() ;
public void destroy() ;

这三个方法都是Thread自带停止或者销毁的方法,不过都被废弃掉了。

为什么会被废弃呢?
     * @deprecated This method was originally designed to force a thread to stop
     *       and throw a {@code ThreadDeath} as an exception. It was inherently unsafe.
     *       Stopping a thread with
     *       Thread.stop causes it to unlock all of the monitors that it
     *       has locked (as a natural consequence of the unchecked
     *       <code>ThreadDeath</code> exception propagating up the stack).  If
     *       any of the objects previously protected by these monitors were in
     *       an inconsistent state, the damaged objects become visible to
     *       other threads, potentially resulting in arbitrary behavior.  Many
     *       uses of <code>stop</code> should be replaced by code that simply
     *       modifies some variable to indicate that the target thread should
     *       stop running.  The target thread should check this variable
     *       regularly, and return from its run method in an orderly fashion
     *       if the variable indicates that it is to stop running.  If the
     *       target thread waits for long periods (on a condition variable,
     *       for example), the <code>interrupt</code> method should be used to
     *       interrupt the wait.

这是stop方法官方注释,大概意思就是:用这个方法停止线程,会出现线程不安全问题。当多个线程访问共享数据时,由于线程被stop了,没有来得及做收尾工作产生脏数据,那么共享数据就有可能被破坏,而这个破坏对于其他线程来说是可见的。而且外部直接通过stop来停止线程,过于暴力,例如我需要得到回调,但是被stop了,根本没有机会stop
既然不能直接暴力地停止线程,要给线程留出收尾的时间,那么我们可以在外部通知线程结束,至于是否结束由线程本身决定。

1.interrupt停止线程
public void interrupt()

(1)这是Thread 实例方法,中断线程;
(2)当线程调用了sleep(),wait(),join()处于阻塞等待,外部interrupt方法,那么线程内部会抛出InterruptedException,在catch异常以后做些以收尾工作结束线程;
(3)如果线程没有因为以上三种方法处于阻塞状态,外部调用其interrupt方法,线程是不会有任何影响的;

场景1:线程sleep10 * 1000毫秒以后,对变量进行加10操作;

模拟代码如下:
开启一个TestThread,休眠10秒对变量data加10,主线程在开启TestThread两秒钟后,调用interrupt中断线程。

    public void testThread(){
        final TestThread testThread = new TestThread();
        testThread.start();
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                testThread.interrupt();
            }
        }, 2 * 1000);//模拟两秒钟后中断线程
    }

    class TestThread extends Thread {

        private int data;

        @Override
        public void run() {
            super.run();
            try {
                sleep(10 * 1000);
                data += 10;//进行运算
                Log.d("test", "data:" + data);
            } catch (InterruptedException e) {
                e.printStackTrace();
                Log.d("test", "data:" + data);
            }
        }
    }

打印日志如下:
从日志中可以看出,线程捕获到InterruptedException异常,变量data并没有被修改,线程任务结束退出。

2020-08-26 11:02:44.413 8969-10530/com.yang.memorytest W/System.err: java.lang.InterruptedException
2020-08-26 11:02:44.414 8969-10530/com.yang.memorytest W/System.err:     at java.lang.Object.wait(Native Method)
2020-08-26 11:02:44.414 8969-10530/com.yang.memorytest W/System.err:     at java.lang.Object.wait(Object.java:442)
2020-08-26 11:02:44.414 8969-10530/com.yang.memorytest W/System.err:     at java.lang.Thread.join(Thread.java:1430)
2020-08-26 11:02:44.415 8969-10530/com.yang.memorytest W/System.err:     at com.yang.memorytest.MainActivity$TestThread.run(MainActivity.java:96)
2020-08-26 11:02:44.415 8969-10530/com.yang.memorytest D/test: data:0
场景2:当线程任务是循环做业务处理,外部调用interrupt方法,循环条件需要增加判断是否被中断,是,则结束线程。

模拟代码如下:
同样开启一个TestThread,对变量data运算,如果data大于等于Integer.MAX_VALUE或者isInterrupted()为true,则跳出循环。主线程在开启TestThread两秒钟后,调用interrupt中断线程。

  public void testThread() {
        final TestThread testThread = new TestThread();
        testThread.start();
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                testThread.interrupt();
            }
        }, 2 * 1000);//模拟两秒钟后中断线程
    }

    class TestThread extends Thread {

        private int data;

        @Override
        public void run() {
            super.run();
            while (data < Integer.MAX_VALUE&&!isInterrupted()) {
                    data += 10;//进行运算
            }
            Log.d("test", "data:" + data);

        }
    }

打印日志如下:
从日志中可以看出,isInterrupted()返回true,循环结束,线程退出。

2020-08-26 12:08:48.469 12078-13614/com.yang.memorytest D/test: isInterrupted():true
2020-08-26 12:08:48.469 12078-13614/com.yang.memorytest D/test: data:9667354
场景3:当线程任务是执行耗时任务,也是可以通过判断isInterrupted来决定是否结束任务。
    class TestThread extends Thread {
        @Override
        public void run() {
            super.run();
            //业务处理1
            if (isInterrupted()) {
                return;
            }
            //业务处理2
            if (isInterrupted()) {
                return;
            }
            //业务处理3
            if (isInterrupted()) {
                return;
            }
        }
    }
2.boolean变量停止线程

该方案与判断isInterrupted是否为true类似。
interrupt底层也是通过设置标记位,而且还加锁保证线程安全,所以boolean变量也要考虑线程安全问问题。
以下TestThread 暴露isStop变量给外部停止线程,大家注意到,变量是被volatile修饰的,因为当多个线程同时需要停止该线程时,每个线程都有自己的内存模型,会导致这个变量不可预知,所以volatile保证修改对于所有线程都是可见的。

    class TestThread extends Thread {

        private int data;
        
        volatile public boolean isStop;

        @Override
        public void run() {
            super.run();
            while (data < Integer.MAX_VALUE&&!isStop) {
                    data += 1;//进行运算
            }
            Log.d("test", "isStop:" +isStop);
            Log.d("test", "data:" + data);

        }
    }
3.以上两种方案对比

(1)interrupt可运用在sleep、wait、join等情况下,而boolean变量不行;
(2)interrupt涉及到jni的调用,而boolean变量只是Java层的;

5.isInterrupted()与interrupted()区别

共同点:两者都是获取中断状态;
isInterrupted是实例方法;调用interrupt()以后,如果中断状态没有被清理(catch InterruptedException或者调用interrupted),isInterrupted()会一直返回true;

public boolean isInterrupted()

interrupted是静态方法;调用interrupt()以后,调用interrupted第一次会返回true,以后就会返回false,因为中断状态被重置了。

public static native boolean interrupted()
6.InterruptedException

查看sleep注释发现,当抛出InterruptedException时,中断状态会被清空,也就是置为false。如果外部想在中断以后,获取到中断状态,建议在catch InterruptedException的时候,再次调用interrupted()方法。

     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    // BEGIN Android-changed: Implement sleep() methods using a shared native implementation.
    public static void sleep(long millis) throws InterruptedException 

以上分析有不对的地方,请指出,互相学习,谢谢哦!

相关文章

  • Java基础-停止Thread

    API 停止线程的方法 这三个方法都是Thread自带停止或者销毁的方法,不过都被废弃掉了。 为什么会被废弃呢? ...

  • 停止线程的方法

    1.停止线程的几种方法 java.lang.Thread#suspend 暂停java.lang.Thread#...

  • Thread类详解以及创建线程的四种方法

    1.Thread 类详解 Thread类是Java语言中重要的基础类,位于java.lang包中。Thread类有...

  • Java基础-Thread

    @see https://juejin.im/entry/57339fe82e958a0066bf284f htt...

  • 多线程2之停止线程

    在java多线程中,停止线程的方法有两种:Thread.stop()和Thread.interruped() st...

  • Java线程

    Java线程基础 线程状态 在Thread.java类文件中,有一个state静态枚举内部类,预定义了Thread...

  • java基础之Thread

    线程 定义线程是程序执行的一条路径,一个进程中可以包含多条线程 优点多线程并发执行可以提高程序的效率, 可以同时完...

  • Java常用包和第三方jar包

    一、Java常用包 java.lang--语言包:Java语言的基础类,包括Object类、Thread类、Str...

  • Thread基础

    记录Java Thread的基础点。 线程的实现 线程的定义有两种方式 继承Thread类 实现Runnable接...

  • JAVA技术知识体系

    java基础 java虚拟机 集合框架 网络编程-Socket 并发编程-Thread io 数据库操作-JDBC...

网友评论

      本文标题:Java基础-停止Thread

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