中断线程一般有三种方法:
1. 循环中设置状态位或者循环中检测线程中断状态
2. 调用interrupt()方法,设置中断,并捕获InterruptedException
3. 调用能响应中断异常的方法或者是带超时的方法
一、设置状态位(或检测线程中断状态)
violate boolean isStop = false;
public void run() {
while(!isStop) {
doSomething....
}
}
public void run() {
while(!Thread.currentThread().isInterrupted()) {
doSomething....
}
}
二、设置中断,并捕获InterruptedException
线程调用sleep()、wait()、join()方法会进入阻塞状态,这些方法会检测线程中断标志位,如果发现中断标志位为true则抛出异常并且将中断标志位设置为false。
public class Test extends Thread{
private boolean flag = true;
public void run() {
while(flag) {
System.out.println(Thread.currentThread().getName() + " is running");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
flag = false;
System.out.println("exit....");
}
}
if (!flag) {
System.out.println(Thread.currentThread().getName() + " is interrupted");
}
}
public static void main(String[] args) {
Test test = new Test();
test.start();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
}
test.interrupt();
}
}
这里使用的flag标志,如果循环条件是判断其中断标志的话如:
while(!Thread.currentThread().isInterrupted()) {
try{
...
}catch(InterruptedException e){
//由于调用sleep()方法清除状态标志位 所以这里需要再次重置中断标志位 否则线程会继续运行下去
Thread.currentThread().interrupt();
}
}
第三种情况一般是线程不能被中断的,如调用synchronized关键字和reentrantLock.lock()获取锁的过程。但是如果调用带超时的tryLock方法reentrantLock.tryLock(longtimeout, TimeUnit unit),那么如果线程在等待时被中断,将抛出一个InterruptedException异常,也可以调用reentrantLock.lockInterruptibly()方法,它就相当于一个超时设为无限的tryLock方法。
作者:郭无心
链接:https://www.zhihu.com/question/36771163/answer/68974735
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
public void lock()
获取锁。
如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。
如果当前线程已经保持该锁,则将保持计数加 1,并且该方法立即返回。
如果该锁被另一个线程保持,则出于线程调度的目的,禁用当前线程,并且在获得锁之前,该线程将一
直处于休眠状态,此时锁保持计数被设置为 1。
public void lockInterruptibly() throws InterruptedException
1)如果当前线程未被中断,则获取锁。
2)如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。
3)如果当前线程已经保持此锁,则将保持计数加 1,并且该方法立即返回。
4)如果锁被另一个线程保持,则出于线程调度目的,禁用当前线程,并且在发生以下两种情况之一以
前,该线程将一直处于休眠状态:
1)锁由当前线程获得;或者
2)其他某个线程中断当前线程。
5)如果当前线程获得该锁,则将锁保持计数设置为 1。
如果当前线程:
1)在进入此方法时已经设置了该线程的中断状态;或者
2)在等待获取锁的同时被中断。
则抛出 InterruptedException,并且清除当前线程的已中断状态。
6)在此实现中,因为此方法是一个显式中断点,所以要优先考虑响应中断,而不是响应锁的普通获取或重入获取。
public boolean tryLock()
仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
1)如果该锁没有被另一个线程保持,并且立即返回 true 值,则将锁的保持计数设置为 1。
即使已将此锁设置为使用公平排序策略,但是调用 tryLock() 仍将 立即获取锁(如果有可用的),
而不管其他线程当前是否正在等待该锁。在某些情况下,此“闯入”行为可能很有用,即使它会打破公
平性也如此。如果希望遵守此锁的公平设置,则使用 tryLock(0, TimeUnit.SECONDS)
,它几乎是等效的(也检测中断)。
2)如果当前线程已经保持此锁,则将保持计数加 1,该方法将返回 true。
3)如果锁被另一个线程保持,则此方法将立即返回 false 值。
1)lock(), 拿不到lock就不罢休,不然线程就一直block。 比较无赖的做法。
2)tryLock(),马上返回,拿到lock就返回true,不然返回false。 比较潇洒的做法。 带时间限制的tryLock(),拿不到lock,就等一段时间,超时返回false。比较聪明的做法。
3)lockInterruptibly()就稍微难理解一些。先说说线程的打扰机制,每个线程都有一个 打扰 标志。这里分两种情况,
1. 线程在sleep或wait,join, 此时如果别的进程调用此进程的 interrupt()方法,此线程会被唤醒并被要求处理InterruptedException;(thread在做IO操作时也可能有类似行为,见java thread api)
2. 此线程在运行中, 则不会收到提醒。但是 此线程的 “打扰标志”会被设置, 可以通过isInterrupted()查看并 作出处理。lockInterruptibly()和上面的第一种情况是一样的, 线程在请求lock并被阻塞时,如果被interrupt,则“此线程会被唤醒并被要求处理InterruptedException”。并且如果线程已经被interrupt,再使用lockInterruptibly的时候,此线程也会被要求处理interruptedException