线程的中断操作
一、Thread.interrupt方法(推荐使用)
/**
* 使用interrupt中断线程
*/
public class InterruptDemo implements Runnable {
@Override
public void run() {
// 判断是否被中断了
while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName());
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new InterruptDemo());
thread.start();
Thread.sleep(1000L);
thread.interrupt();
}
}
二、错误,自行定义一个标志,用来判断是否继续执行(使用volatile)
貌似可以中断线程,但实则遇到阻塞就无法中断线程
/**
* 自定义变量使用volatile修饰.来中断线程
*/
public class MyInterruptDemo implements Runnable {
private static volatile boolean FLAG = true;
@Override
public void run() {
while (FLAG) {
System.out.println(Thread.currentThread().getName());
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new MyInterruptDemo());
thread.start();
Thread.sleep(1000L);
FLAG = false;
}
}
陷入阻塞时,volatile是无法中断线程
演示用volatile的局限part2 陷入阻塞时,volatile是无法中断线程的 此例中,生产者的生产速度很快,
消费者消费速度慢,所以阻塞队列满了以后,生产者会阻塞,等待消费者进一步消费
/**
* 描述: 演示用volatile的局限part2 陷入阻塞时,volatile是无法中断线程的 此例中,生产者的生产速度很快,
* 消费者消费速度慢,所以阻塞队列满了以后,生产者会阻塞,等待消费者进一步消费
*/
public class WrongWayVolatileCantStop {
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue storage = new ArrayBlockingQueue(10);
Producer producer = new Producer(storage);
Thread producerThread = new Thread(producer);
producerThread.start();
Thread.sleep(1000);
Consumer consumer = new Consumer(storage);
while (consumer.needMoreNums()) {
System.out.println(consumer.storage.take()+"被消费了");
Thread.sleep(100);
}
System.out.println("消费者不需要更多数据了。");
//一旦消费不需要更多数据了,我们应该让生产者也停下来,但是实际情况
producer.canceled=true;
System.out.println(producer.canceled);
}
}
class Producer implements Runnable {
public volatile boolean canceled = false;
BlockingQueue storage;
public Producer(BlockingQueue storage) {
this.storage = storage;
}
@Override
public void run() {
int num = 0;
try {
while (num <= 100000 && !canceled) {
if (num % 100 == 0) {
storage.put(num);// 阻塞在这步,导致无法中断线程
System.out.println(num + "是100的倍数,被放到仓库中了。");
}
num++;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("生产者结束运行");
}
}
}
class Consumer {
BlockingQueue storage;
public Consumer(BlockingQueue storage) {
this.storage = storage;
}
public boolean needMoreNums() {
if (Math.random() > 0.95) {
return false;
}
return true;
}
}
三、Thread.stop()方法(废弃,不能使用会造成严重事故)
/**
* 使用thread.stop()停止线程,不要使用
*/
public class Demo implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Demo());
thread.start();
Thread.sleep(2000L);
thread.stop();
}
}
四、interrupt需要注意的
注意如下操作会清空清空中断标识
- 调用Thread.interrupted()方法可以获取中断状态并会清空中断标识
- 抛出InterruptedException异常会清空中断标识
当run方法中存在sleep或wait方法时,停止线程需要注意可能会抛出InterruptedException异常会,导致中断失败,需要注意try--catch的用法
4.1 循环里面放try/catch,会导致中断失效
/**
* 描述: 如果while里面放try/catch,会导致中断失效
*/
public class CantInterrupt {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = () -> {
int num = 0;
while (num <= 10000 && !Thread.currentThread().isInterrupted()) {
if (num % 100 == 0) {
System.out.println(num + "是100的倍数");
}
num++;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread thread = new Thread(runnable);
thread.start();
Thread.sleep(5000);
thread.interrupt();
}
/**
* 此时虽然调用了thread.interrupt();方法,但是由于线程的状态存在阻塞,
* 所以会抛出java.lang.InterruptedException: sleep interrupted异常
* 如果在循环里面放try/catch,会导致中断失效,即使捕获了异常也不会停止线程
*
* 输出结果如下
*
* 0是100的倍数
* 100是100的倍数
* 200是100的倍数
* 300是100的倍数
* 400是100的倍数
* java.lang.InterruptedException: sleep interrupted
* at java.lang.Thread.sleep(Native Method)
* at com.liyc.concurrency.threadcoreknowledge.stopthreads.CantInterrupt.lambda$main$0(CantInterrupt.java:17)
* at java.lang.Thread.run(Thread.java:748)
* 500是100的倍数
* ...
*
*
*/
}
4.2 如果在执行过程中,每次循环都会调用sleep或wait等方法,那么不需要每次迭代都检查是否已中断
/**
* 描述: 如果在执行过程中,每次循环都会调用sleep或wait等方法,那么不需要每次迭代都检查是否已中断
*/
public class RightWayStopThreadWithSleepEveryLoop {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = () -> {
int num = 0;
try {//在循环外卖try catch可以捕获异常,并中断异常
while (num <= 10000) {
if (num % 100 == 0) {
System.out.println(num + "是100的倍数");
}
num++;
Thread.sleep(10);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Thread thread = new Thread(runnable);
thread.start();
Thread.sleep(2000);
thread.interrupt();
}
/**
* 如果在执行过程中,每次循环都会调用sleep或wait等方法,那么不需要每次迭代都检查是否已中断
*
* 输出结果:
* 0是100的倍数
* 100是100的倍数
* java.lang.InterruptedException: sleep interrupted
* at java.lang.Thread.sleep(Native Method)
* at com.liyc.concurrency.threadcoreknowledge.stopthreads.RightWayStopThreadWithSleepEveryLoop.lambda$main$0(RightWayStopThreadWithSleepEveryLoop.java:16)
* at java.lang.Thread.run(Thread.java:748)
*/
}
网友评论