欢迎您的访问
专注架构,Java,数据结构算法,Python技术分享

二、网络编程之线程停止详解

引言

多线程中有三种方式可以停止线程。
设置标记位,可以是线程正常退出。
使用stop方法强制使线程退出,但是该方法不太安全所以已经被废弃了。
使用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...

使用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...

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

使用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次执行
退出了

 

赞(1) 打赏
版权归原创作者所有,任何形式转载请联系作者;码农code之路 » 二、网络编程之线程停止详解

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏