002-二、网络编程之线程停止详解
引言
多线程中有三种方式可以停止线程。
设置标记位,可以是线程正常退出。
使用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次执行
退出了
写完了如果写得有什么问题,希望读者能够给小编留言,也可以点击[此处扫下面二维码关注微信公众号](https://www.ycbbs.vip/?p=28 "此处扫下面二维码关注微信公众号")
看完两件小事
如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:
- 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
- 关注公众号 「方志朋」,公众号后台回复「666」 免费领取我精心整理的进阶资源教程
本文著作权归作者所有,如若转载,请注明出处
转载请注明:文章转载自「 Java极客技术学习 」https://www.javajike.com