主要包括以下二大方面:
- 被弃用的stop,suspend,resume方法
- 用volatile设置boolean标记位
- 停止线程相关重要函数
- 停止线程面试题
第一:
采用stop方法来停止线程,会导致线程运行到一半突然停止,没办法完成一个基本单位的操作,会造成脏读数据,且会释放监视锁
suspend方法不会释放锁,容易造成死锁
第二:
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对象引用的interrupt()方法,并在run方法中使用Thread.currentThread().isInterrupted(),
/**
* 描述: 用中断来修复刚才的无尽等待问题
*/
public class WrongWayVolatileFixed {
public static void main(String[] args) throws InterruptedException {
WrongWayVolatileFixed body = new WrongWayVolatileFixed();
ArrayBlockingQueue storage = new ArrayBlockingQueue(10);
Producer producer = body.new Producer(storage);
Thread producerThread = new Thread(producer);
producerThread.start();
Thread.sleep(1000);
Consumer consumer = body.new Consumer(storage);
while (consumer.needMoreNums()) {
System.out.println(consumer.storage.take() + "被消费了");
Thread.sleep(100);
}
System.out.println("消费者不需要更多数据了。");
producerThread.interrupt();//重点在这
class Producer implements Runnable {
BlockingQueue storage;
public Producer(BlockingQueue storage) {
this.storage = storage;
}
@Override
public void run() {
int num = 0;
try {
//还有这
while (num <= 100000 && !Thread.currentThread().isInterrupted()) {
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;
}
}
}
第三:
判断线程是否已经被中断的方法
- static boolean interrupted():会清除当前线程中断状态
- boolean isInterrupted():不清除线程中断状态
- Thread.interrupted:此方法的目标对象是当前线程,而不管本方法无法来自哪个对象
代码demo:
public class RightWayInterrupted {
public static void main(String[] args) throws InterruptedException {
Thread threadOne = new Thread(new Runnable() {
@Override
public void run() {
for (; ; ) {
}
}
});
// 启动线程
threadOne.start();
//设置中断标志
threadOne.interrupt();
//获取中断标志
System.out.println("isInterrupted: " + threadOne.isInterrupted());
//获取中断标志并重置
System.out.println("isInterrupted: " + threadOne.interrupted());
//获取中断标志并重直
System.out.println("isInterrupted: " + Thread.interrupted());
//获取中断标志
System.out.println("isInterrupted: " + threadOne.isInterrupted());
threadOne.join();
System.out.println("Main thread is over.");
}
}
运行结果为:
isInterrupted: true,当前线程已经给中断信号,所以能接收到中断信息
isInterrupted: false,所调用的方法为静态的方法,该方法会清除中断信息,获取不到
isInterrupted: false,此时该方法的目标对象是main线程,而main线程没有谁来发中断信号,也就获取不到中断信息了
isInterrupted: true,该方法不会清除中断信号,因此可以接收到
第四:
1.如何停止线程?,可以分为以下情况来回答
- 原理,用interrupt来请求,好处
- 想停止线程,要请求方法,被停止方,子方法被调用的配合
- 最后再说错误的方法,:stop/suspend,volatile修饰的boolean无法处理长时间阻塞的情况
2.如何处理不可中断的阻塞(ReentrantLock,和IO)?
针对不同的情况,采取不同的策略,并用能够响应中断的类,比如ReentrantLock的lock方法,可以用其interrupted方法