文章目录
谈谈多线程中终止线程的三个方法
前言
最近闲来无事,临近五一,便重拾起了《java多线程编程核心技术》一书,再看至线程终止这一小节,有自己一些特别的总结,分享出来。
停止线程
一、使用推出标志使线程退出
1.1、使用interrupt()方法
首先我们先来看一个interrupt()方法的使用案例
首先先创建一个mythread类
public class mythread extends Thread{
@Override
public void run() {
super.run();
System.out.println(Thread.interrupted());
for (int i = 0; i <5000 ; i++) {
System.out.println("i="+i);
}
}
}
创建一个测试类
public class test {
public static void main(String[] args) throws InterruptedException {
mythread mythread = new mythread();
mythread.start();
// Thread.sleep(200);
mythread.interrupt();
// System.out.println(Thread.interrupted());
// System.out.println(Thread.interrupted());
System.out.println("a1234");
}
}
输出结果如下:
我们可以看到,尽管我们使用了interrupt()方法进行停止,但是线程依旧在执行,输出到了4999,这是为什么呢?
原因在于,我们使用了interrupt方法时只是给当前线程打上了一个让你停止的标志,并不是直接让你停止下来!
那么我们应该怎么让他真正的停下来呢?
我们需要先掌握判断线程是不是被打上了停止标记
1.2、判断线程是不是打上了停止的标志
在java的jdk中,Thread.java类中提供了两种判断方法
- 静态方法 public static boolean interrupted()
- public boolean isInterrupted()
那么这两个方法有什么区别呢?我们来看看以下代码!
public class test {
public static void main(String[] args) throws InterruptedException {
mythread mythread = new mythread();
mythread.start();
// Thread.sleep(200);
Thread.currentThread().interrupt();
mythread.interrupt();
System.out.println(Thread.interrupted());
System.out.println(Thread.interrupted());
System.out.println("a1234");
}
}
结果如下:
我们可以看到,该方法确实判断了线程的停止状态,但是第一次是true后,为什么第二次判断又是flase了呢?
官方文档的解释如下:
测试当前线程是否已经中断,并且线程的中断状态由该方法清除,也就是说,你在第一次调用方法后,会清除停止状态标志位。此时线程并未被打上停止标志位
我们再来看看isinterruped()这个方法,这个方法并不是静态方法,所以需要线程本身进行调用,测试案例如下:
public class mythread extends Thread{
@Override
public void run() {
super.run();
System.out.println(this.isInterrupted());
System.out.println(this.isInterrupted());
for (int i = 0; i <5000 ; i++) {
System.out.println("i="+i);
}
}
}
输出结果如下:
我们可以看到这个方法也给线程打上了停止标志位,并且调用完后,保持着标志位,并没有清除!
总结一下这两个方法的解释:
1)Thread.interruped():测试当前线程是否已经中断,执行后清楚线程的停止状态标志
2)this.isInterruped():测试当前线程是否终端,不清楚标志位
既然知道了判断是否具有停止标志位的方法:
那我们想要终止线程是不是可以在线程里判断是否具有停止标志位,有的话就在线程里停止线程呢?
异常法停止线程
根据上面所叙述的,我们只需要在for循环里首先判断是不是具有停止状态位,有的话直接抛出异常,这样就实现了停止线程的功能,测试代码如下:
//myrhread类
public class mythread extends Thread{
@Override
public void run() {
super.run();
try {
for (int i = 0; i <500000 ; i++) {
if (this.isInterrupted())
{
System.out.println("停止咯");
throw new InterruptedException();
}
System.out.println("i="+i);
}
System.out.println("我在for下面");
}
catch (InterruptedException e) {
System.out.println("线程被catch了");
e.printStackTrace();
}
}
}
//测试类
public class test {
public static void main(String[] args) throws InterruptedException {
mythread mythread = new mythread();
mythread.start();
Thread.sleep(200);
// Thread.currentThread().interrupt();
mythread.interrupt();
// System.out.println(Thread.interrupted());
// System.out.println(Thread.interrupted());
System.out.println("a1234");
}
}
运行结果如下:
我们可以看到线程确实被停止了!
在sleep中线程被停止
在sleep状态下,如果线程被打上了停止标记,则会直接被catch到,停止线程,测试代码如下:
public class mythread extends Thread{
@Override
public void run() {
super.run();
try {
System.out.println("线程开始");
Thread.sleep(2000);
System.out.println("线程停止");
} catch (InterruptedException e) {
System.out.println("进行到catch里面咯");
e.printStackTrace();
}
}
}
public class test {
public static void main(String[] args) throws InterruptedException {
mythread mythread = new mythread();
mythread.start();
Thread.sleep(200);
// Thread.currentThread().interrupt();
mythread.interrupt();
// System.out.println(Thread.interrupted());
// System.out.println(Thread.interrupted());
System.out.println("a1234");
}
}
我们可以看到sleep方法下面的代码并未被执行,说明一遇到sleep方法后,线程就直接进入catch了,线程也停止了!
使用return方法停止线程
我们也可以直接使用return方法停止线程,只要一判断到线程被打上了停止标志位,则立马退出函数,也起到了停止线程的作用。大家可以自行演示一下!
二、使用stop方法强行终止线程
该方法并不推荐使用!已经是过期作废的方法,原因很简单,该方法是暴力停止线程,不管你的线程进行到了什么地步,这就会导致一个原因,你上锁的方法还没执行完,直接被释放锁,数据就是个半成品数据,其他线程调用你线程的数据时,就会出现数据错误的情况!我们可以看看一下的案例:
mysercive类
public class mysercice {
private String username="a";
private String passward="aa";
public String getUsername() {
return username;
}
public String getPassward() {
return passward;
}
synchronized public void print1(String username,String passward){
try {
this.username=username;
Thread.sleep(1000000);
this.passward=passward;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
两个线程类:
//线程一
public class mythread extends Thread{
private mysercice mysercice;
public mythread(mysercice mysercice) {
this.mysercice = mysercice;
}
@Override
public void run() {
super.run();
mysercice.print1("b","bb");
}
}
//线程二
public class mythread1 extends Thread{
private mysercice mysercice;
public mythread1(mysercice mysercice) {
this.mysercice = mysercice;
}
@Override
public void run() {
super.run();
System.out.println(mysercice.getUsername()+" "+mysercice.getPassward());
}
}
测试类:
public class test {
public static void main(String[] args) throws InterruptedException {
mysercice mysercice = new mysercice();
mythread mythread = new mythread(mysercice);
mythread1 mythread1 = new mythread1(mysercice);
mythread.start();
Thread.sleep(200);
mythread1.start();
mythread.stop();
}
}
结果如下:
可以看出,数据出现了错误,我们在使用stop方法后,线程一锁被释放了,还没有给passward赋值时就已经进入了catch里,数据没有按照我们预想的来处理,出现了半成品数据,这时线程二已经进行了打印,所以出现了这种情况!