Java多线程编程-Thread API
- Thread.interrupt()方法
- Thread.interrupted()方法
- Thread.isInterrupted()方法
- 发生异常中断线程
- 在线程sleep的时候调用interrupt()方法
- 使用return停止线程
上面我们看了Thread类中的currentThread()方法,sleep()方法,getId()方法,isAlive()方法,现在我看看其他的一些API
Thread.interrupt()方法
interrupt():中断该线程,除非始终允许当前线程中断自身,否则将调用安全检查,有可能会抛出安全异常
源码:
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
//blockerLock 为声明的一个锁
synchronized (blockerLock) {
//如果存在中断,则该线程在可中断的IO操作中被阻塞的对象。设置此线程的中断状态后,应调用阻塞程序的中断方法。
Interruptible b = blocker;
if (b != null) {
interrupt0(); // 仅仅去设置一个中断标记
b.interrupt(this);
return;
}
}
interrupt0();
}
我们进行测试一下这个方法
public class ThreadInterruptV1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
System.out.println("current i value : " + i);
}
}
}
运行代码:
public class ThreadInterruptV1Main {
public static void main(String[] args) throws InterruptedException {
ThreadInterruptV1 threadInterruptV1 = new ThreadInterruptV1();
threadInterruptV1.start();
Thread.sleep(1000);
threadInterruptV1.interrupt(); //中断该线程
}
}
运行结果:
有运行可以看到,ThreadInterruptV1这个线程没有中断,还是执行完成了,怎么回事呢?有我们上面的源码可以看出,在调用这个方法的时候只会在当前线程打上一个中断的标记。那我们怎么获取线程是否中断,可以使用下面两个api
Thread.interrupted()方法
interrupted():测试当前线程是否已被中断,通过这个方法会清除线程的中断状态,如果连续调用两次此方法,则第二次调用会返回false,除非当前线程在第一次调用清除其中断状态之后且在第二次调用检查其状态之前再次中断。由于此方法返回false,因此将反映线程中断,因为该线程在中断时尚未处于活动状态而被忽略。
源码:
public static boolean interrupted() {
//调用了isInterrupted,清除中断状态是调用isInterrupted(true)导致,true为清除冲断状态
return currentThread().isInterrupted(true);
}
我们来验证一下:
public class ThreadInterruptV1MainV2 {
public static void main(String[] args) throws InterruptedException {
ThreadInterruptV1 threadInterruptV1 = new ThreadInterruptV1();
threadInterruptV1.start();
Thread.sleep(1000);
threadInterruptV1.interrupt();
System.out.println("threadInterruptV1 interrupt status:" + threadInterruptV1.interrupted());
System.out.println("threadInterruptV1 interrupt status:" + threadInterruptV1.interrupted());
}
}
运行结果如下:
这里打印为什么都为false呢?interrupted是判断当前线程是否中断,这里的当前线程为main线程,main线程从来没有被中断过,所以会打印出两个false。
在来测试看看调用两次的情况
public class ThreadInterruptV1MainV3 {
public static void main(String[] args) {
Thread.currentThread().interrupt();
System.out.println("current thread interrupt status:" + Thread.interrupted());
System.out.println("current thread interrupt status:" + Thread.interrupted());
}
}
运行结果:
验证了通过这个方法会清除线程的中断状态,如果连续调用两次此方法,则第二次调用会返回false
Thread.isInterrupted()方法
isInterrupted():测试此线程是否已被中断。线程的中断状态不受此方法的影响。 由于此方法返回false,因此将反映线程中断,因为该线程在中断时尚未处于活动状态而被忽略。
源码:
public boolean isInterrupted() {
return isInterrupted(false);
}
方法不是一个静态的,所以需要实例化才能使用。
验证一下:
public class ThreadInterruptV1MainV2 {
public static void main(String[] args) throws InterruptedException {
ThreadInterruptV1 threadInterruptV1 = new ThreadInterruptV1();
threadInterruptV1.start();
Thread.sleep(1000);
threadInterruptV1.interrupt();
System.out.println("threadInterruptV1 interrupt status:" + threadInterruptV1.isInterrupted());
System.out.println("threadInterruptV1 interrupt status:" + threadInterruptV1.isInterrupted());
}
}
运行结果:
从运行结果看出,isInterrupted方法不会影响线程的中断标记。
上面的都没有中断线程,因为后面的代码还在进行,那我们怎么中断线程呢?
发生异常中断线程
我们知道interruped()方法会给线程打一个中断标记
验证:
public class ThreadInterruptV2 extends Thread {
@Override
public void run() {
for (int i = 0; i < 50000; i++) {
if (this.isInterrupted()) {
System.out.println("this thread had interrupted");
break;
}
System.out.println("current i value : " + i);
}
System.out.println("this code run end");
}
}
运行代码:
public class ThreadInterruptV2Main {
public static void main(String[] args) throws InterruptedException {
ThreadInterruptV2 threadInterruptV2 = new ThreadInterruptV2();
threadInterruptV2.start();
Thread.sleep(1000);
threadInterruptV2.interrupt();
System.out.println("main method code end");
}
}
运行结果:
通过运行结果可以看到,当线程中断之后,for循环退出了,但是for后面的代码还会执行,这里说明中断标记打上了,但是线程还没有停止。
我们在for循环中主动抛出一个看看
public class ThreadInterruptV3 extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 50000; i++) {
if (this.isInterrupted()) {
System.out.println("current thread is interrupted");
throw new InterruptedException();
}
System.out.println("current i value:" + i);
}
System.out.println("this thread code end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行的结果:
当抛出异常的时候可以停止线程,后面的代码没有执行了。
在线程sleep的时候调用interrupt()方法
在线程sleep中的时候,进行调用的interrupt()会抛出中断的异常,同时会修改线程的中断状态。在sleep方法API的javadoc中查到
进行验证
public class ThreadInterruptV4Main {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
for (int i = 0; i < 50000; i++) {
System.out.println("current i value:" + i);
try {
Thread.sleep(20000); //线程进行睡眠
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
thread.interrupt();
}
}
运行结果:
所以尝试给sleep中的睡眠中断的话,将会出现中断异常。
使用return停止线程
使用return也可以停止一个正在运行的线程
验证:
public class ThreadInterruptV5Main {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (Thread.interrupted()) {
System.out.println("current thread is interrupted");
return;
}
}
}
});
thread.start();
thread.interrupt();
}
}
运行结果:
可以看到线程已经停止了。