怎样让线程停止

12 篇文章 0 订阅
7 篇文章 0 订阅

上一篇文章讲到了interrupt()、interrupted()、isInterrupted()这三个方法,最后留了个尾巴,那么今天这一篇文章就给大家讲一下怎样停止线程。

stop()方法

说到线程停止,第一个想到的办法就是Thread类的stop()方法,下面就先讲一下stop()方法。

@Deprecated
public final void stop() {
    ...
}

stop()方法可以暴力的停止一个线程,直接打断线程的运行。

但是我们可以观察到stop()方法被@Deprecated修饰,标明是一个废弃的方法,不建议使用,那么下面我们就来说一下使用stop()方法可能带来的一些问题。

1.调用stop()方法会抛出java.lang.ThreadDeath错误

public class StopTest {

    public static void main(String[] args) {
        TestStopThread t1 = new TestStopThread();
        t1.start();
    }

}

class TestStopThread extends Thread {
    @Override
    public void run() {
        try {
            this.stop();
        } catch (ThreadDeath e) {
            System.out.println("抛出ThreadDeath异常" + e.toString());
            e.printStackTrace();
        }
    }
}

2.破坏锁,导致数据不一致。

大家都知道用synchronized关键字修饰一个方法的时候,可以保证这个方法是原子性的,而stop()方法被调用时会直接释放锁,可能会导致数据不一致。

大家可以看看下面这个案例:

public class StopLockTest {
    public static void main(String[] args) {
        StopLockThread stopLockThread = new StopLockThread();
        Thread t1 = new Thread(stopLockThread);
        t1.start();
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
//        t1.stop();
        Thread t2 = new Thread(stopLockThread);
        t2.start();
    }
}

class StopLockThread extends Thread {

    @Override
    public void run() {
        testSync();
    }

    public synchronized void testSync() {
        System.out.println("start sync");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end sync");
    }
}

执行上面这一段代码控制台输出

t1:start sync1532259460591
t1:end sync1532259461591
t2:start sync1532259461591
t2:end sync1532259462593

我们可以得到结论,t1、t2两个线程会同步的进入testSync()方法

而如果我们将t1.stop();的注释去掉,执行上面这一段代码控制台将输出

t1:start sync1532259482124
t2:start sync1532259482145
t2:end sync1532259483146

由于第一行输出和第二行输出时间戳只相差21毫秒,所以我们可以得出结论,t1.stop()直接打断了t1线程的运行,并且直接释放了testSync()方法的锁。

既然stop()方法存在这些问题,并且已经在JDK中被标注为废弃方法,所以强烈不建议在程序中使用stop()方法。

使用interrupt()方法停止线程

下面开始讲解上一篇文章留下的小尾巴了。

上一篇文章明确说明了interrupt()方法不会停止线程,只是会修改线程的interrupted状态,那么我们可以在线程中通过isInterrupted()方法来获取到线程的interrupted状态,然后通过异常或者return的方法来中止线程的运行。

public class ErrorStopTest {
    public static void main(String[] args) {
        ErrorStopThread t1 = new ErrorStopThread();
        t1.start();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t1.interrupt();
    }
}

class ErrorStopThread extends Thread {

    @Override
    public void run() {
        try {
            while (true) {
                if (this.isInterrupted()) {
                    System.out.println("线程interrupted状态为true,抛出异常中止线程");
                    throw new InterruptedException();
                }
                System.out.println(System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

上面这一段代码就是使用interrupt()方法和抛异常相结合的实现中止线程的方法,当然了使用return方法的原理也一致,主要步骤就是:
- 子线程中使用isInterrupted()方法来判断线程的interrupted状态
- 如果子线程的interrupted状态为true,那么结束线程执行的方法
- 主线程可以使用线程的interrupt()来修改子线程的interrupted状态

使用interrupt()方法停止线程相对于stop()方法要安全许多,所以强烈建议使用interrupt()方法来实现线程的停止。

题外话

线程停止的东西到这里就说完了,但是大家可能会发现上面代码中所有线程的sleep()方法都使用try-catch抓取了一个InterruptedException异常。

那么就说明sleep()方法会抛出InterruptedException异常,这里就再提一句
- 在线程interrupted状态为true时调用sleep方法时会抛出InterruptedException异常

@Test
public void interruptSleep(){
    Thread.currentThread().interrupt();
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        System.out.println("进入InterruptedException异常了");
        e.printStackTrace();
    }
}
  • 在线程处于sleep状态的时候调用interrupt()方法会抛出InterruptedException异常
public class SleepInterruptTest {
    public static void main(String[] args) {
        SleepInterruptThread t1 = new SleepInterruptThread();
        t1.start();
        t1.interrupt();
    }

}

class SleepInterruptThread extends Thread {

    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            System.out.println("进入InterruptedException异常了");
            e.printStackTrace();
        }
    }
}

上面两段测试代码都会被捕获到InterruptedException异常,打印”进入InterruptedException异常了”这句话

喜欢文章的,扫码关注微信公众号
扫码关注

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值