java interrupt stop_线程的终止-面试题stop和interrupt方法区别?

了解了线程的生命周期之后,我们知道,一个线程执行完run方法,或者发生异常之后都会自动终止。

但是,这里要说的是在一个线程A中去终止另一个线程B的情况。

在Thread类里面有2个方法可以达到此目的。stop()和interrupt()

stop()方法:用stop() 方法会真的杀死线程,不给线程喘息的机会,如果线程持有 ReentrantLock 锁,被 stop() 的线程并不会自动调用 ReentrantLock 的 unlock() 去释放锁,那其他线程就再也没机会获得 ReentrantLock 锁,这实在是太危险了。所以该方法就不建议使用了,类似的方法还有 suspend() 和 resume() 方法,这两个方法同样也都不建议使用了

比如说下方的i++的例子,我们是通过Lock的方式实现原子操作的。

public void addI() {

lock.lock();

try {

i++;

} finally {

lock.unlock();

}

}

复制代码

这样会出现什么问题呢?当线程A执行时,线程B终止了A的操作,如果A恰好持有共享锁lock,那么它并不会执行unlock操作,导致想获得锁的线程B永远也不能获得锁(不过有的同学可能说给lock加个超时,这个就另说了)

ps:如果是synchronized实现的原子操作,是会主动释放锁的。synchronized原理参考之前写的这篇:大彻大悟synchronized原理,锁的升级

interrupt():从线程的生命周期了解到,一个线程要终止,必须要从runnable状态到terminated。而线程可能处于休眠状态,interrupt方法恰好提供了此功能,它可以将休眠状态的线程转换到runnable状态,并置标志位为true(此时Thread.currentThread().isInterrupted()==true)。

那么线程B调用了线程A的interrupt方法,就能终止线程A吗?

有2种情况:

线程处于waiting或者time_waiting状态:当线程 A 处于 WAITING、TIMED_WAITING 状态时,如果线程B调用线程 A 的 interrupt() 方法,会使线程 A 返回到 RUNNABLE 状态,同时线程 A 的代码会触发 InterruptedException 异常。转换到 WAITING、TIMED_WAITING 状态的触发条件,都是调用了类似 wait()、join()、sleep() 这样的方法,我们看这些方法的签名,发现都会 throws InterruptedException 这个异常。这个异常的触发条件就是:其他线程调用了该线程的 interrupt() 方法。

有一点需要注意的是,抛出异常之后JVM 的异常处理会清除线程的中断状态,我们需要用Thread.currentThread().interrupt() 重新设置了线程的中断状态

非waiting状态:这种状态下,线程B调用线程A的interrupt方法,线程A通过Thread.currentThread().isInterrupted()能判断到自己已被中断,

然后自己结束。

所以结合上面2中情况,我们有了下面的例子:

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class StopInterruptTest {

private int i = 0;

Lock lock = new ReentrantLock();

public static void main(String[] args) {

StopInterruptTest test = new StopInterruptTest();

Thread t1 = new Thread(() -> {

// 中断标志判断

while (!Thread.currentThread().isInterrupted()) {

test.addI();

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

// 重置标志位

Thread.currentThread().isInterrupted();

}

}

});

t1.start();

// main线程打断线程t1

t1.interrupt();

}

public void addI() {

lock.lock();

try {

i++;

} finally {

lock.unlock();

}

}

}

复制代码

但是这样可能有其他问题,就是:如果在t1线程里面,执行的是其他的业务逻辑,其他的业务逻辑并没有正确的处理中断标志。这样就可能出现其他诡异问题。

我们要做的就是,设置自己的标志位,封装自己的终止方法等。比如下面的interruptFlag。

public class StopInterruptTest {

volatile boolean interruptFlag = false;

public static void main(String[] args) {

StopInterruptTest test = new StopInterruptTest();

test.testInterrupt();

}

public void testInterrupt() {

Thread t1 = new Thread(() -> {

// 中断标志判断

while (!interruptFlag) {

// 其它业务

// test.addI();

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

// 重置标志位

Thread.currentThread().isInterrupted();

}

}

});

t1.start();

// main线程打断线程t1

myInterrupt(t1);

}

public synchronized void myInterrupt(Thread t) {

interruptFlag = true;

t.interrupt();

}

}

复制代码

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值