初学者第61节之线程停止详解(三)

引言

多线程中有三种方式可以停止线程。

  1. 设置标记位,可以是线程正常退出。
  2. 使用stop方法强制使线程退出,但是该方法不太安全所以已经被废弃了。
  3. 使用Thread类中的一个interrupt() 可以中断线程。

设置标记位停止线程

先看代码

class MyRunnable implements Runnable {
    /**
     * 定义一个关闭线程的标记,首先为false
      */
    private boolean flag = true;
    @Override
    public void run() {
        int i = 1;
        try {
            while (flag) {//这里是无限循环
                Thread.sleep(1000);//为了演示效果所以加上了休眠
                 System.out.println("第" + (i) + "次执行,线程名称" + Thread.currentThread().getName());
                 i++;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /**
     * 将标记设置为false
     */
    public void setFlag() {
        this.flag = false;
    }
}
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.setName("A...");
thread.start();//启动线程
Thread.sleep(3000);//设置2秒之后在停止线程
myRunnable.setFlag();//设置停止线程的状态
结果:
第1次执行,线程名称A...
第2次执行,线程名称A...
第3次执行,线程名称A...

以上大家可以看出来了吧,其实就是在循环的条件上做手脚就好了,因为每次循环都会根据这个while条件来判断的,所以在开启线程之后休眠3秒之后在将while条件设置为false就可以跳出循环了,随之也会自动停止线程了。

使用stop方法强制使线程退出

使用stop方法强制使线程退出,但是该方法不太安全所以已经被废弃了。

为什么说不安全呢?因为stop会解除由线程获取的所有锁定,当在一个线程对象上调用stop()方法时,这个线程对象所运行的线程就会立即停止,假如一个线程正在执行:synchronized void { x = 3; y = 4;} 由于方法是同步的,多个线程访问时总能保证x,y被同时赋值,而如果一个线程正在执行到x = 3;时,被调用了 stop()方法,即使在同步块中,它也会马上stop了,这样就产生了不完整的残废数据。

这个演示也不是每次都能测试出来的。所以就演示一下怎么使用stop吧!

MyRunnable类代码不变,修改一下执行代码即可。

MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.setName("A...");
thread.start();//启动线程
Thread.sleep(3000);//设置2秒之后在停止线程
thread.stop();//设置停止线程的状态
结果:
第1次执行,线程名称A...
第2次执行,线程名称A...

使用Thread类中的一个interrupt()

interrupt() 方法只是改变中断状态而已,它不会中断一个正在运行的线程。这一方法实际完成的是,给受阻塞的线程发出一个中断信号,这样受阻线程就得以退出阻塞的状态。

然而interrupte()方法并不会立即执行中断操作;具体而言,这个方法只会给线程设置一个为true的中断标志(中断标志只是一个布尔类型的变量),而设置之后,则根据线程当前的状态进行不同的后续操作。如果,线程的当前状态处于非阻塞状态,那么仅仅是线程的中断标志被修改为true而已;如果线程的当前状态处于阻塞状态,那么在将中断标志设置为true后,还会有如下三种情况之一的操作:

  • 如果是wait、sleep以及jion三个方法引起的阻塞,那么会将线程的中断标志重新设置为false,并抛出一个InterruptedException;
  • 如果是java.nio.channels.InterruptibleChannel进行的io操作引起的阻塞,则会对线程抛出一个ClosedByInterruptedException;(待验证)
  • 如果是轮询(java.nio.channels.Selectors)引起的线程阻塞,则立即返回,不会抛出异常。(待验证)

如果在中断时,线程正处于非阻塞状态,则将中断标志修改为true,而在此基础上,一旦进入阻塞状态,则按照阻塞状态的情况来进行处理;例如,一个线程在运行状态中,其中断标志被设置为true之后,一旦线程调用了wait、jion、sleep方法中的一种,立马抛出一个InterruptedException,且中断标志被程序会自动清除,重新设置为false。

通过上面的分析,我们可以总结,调用线程类的interrupted方法,其本质只是设置该线程的中断标志,将中断标志设置为true,并根据线程状态决定是否抛出异常。因此,通过interrupted方法真正实现线程的中断原理是:开发人员根据中断标志的具体值,来决定如何退出线程。

下面将演示。

class MyRunnable implements Runnable {
    @Override
    public void run() {
        int i = 1;
        try {
            //这里是无限循环
            while (true) {
                /**
                 * 这里阻塞之后,线程被调用了interrupte()方法,
                 * 清除中断标志,就会抛出一个异常
                 * java.lang.InterruptedException
                 */
                Thread.sleep(1000);
                /**
                 * 运行状态,线程被调用了interrupte()方法,中断标志被设置为true
                 * 非阻塞状态中进行中断线程操作,因为上面有Thread.sleep(1000)
                 * 所以已经睡眠阻塞了那么这块代码是不会执行的。
                 */
                boolean bool = Thread.currentThread().isInterrupted();
                if (bool) {
                    System.out.println("非阻塞情况下执行该操作。。。线程状态" + bool);
                    break;
                }
                System.out.println("第" + (i) + "次执行");
                i++;
            }
        } catch (Exception e) {
            System.out.println("退出了");
            /**
             * 这里退出阻塞状态,且中断标志被系统会自动清除,
             * 并且重新设置为false,所以此处bool为false
             */
            boolean bool = Thread.currentThread().isInterrupted();
            System.out.println(bool);
            return;  //退出run方法,中断进程
        }
    }

代码中的注释还是比较详细的。

执行代码

MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
Thread.sleep(3000);
thread.interrupt();//中断线程,将中断标识设置成true

结果:

第1次执行
第2次执行
退出了

本文分享自微信公众号 - Java研发军团(ityuancheng)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-04-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励