线程优雅关闭
1.暴力停止
从外部直接调用该线程的 stop 方法,直接把线程停下来。会造成数据不一致。不推荐,并且方法已经过时。
2.使用变量通知
通过volatile
关键字定义一个变量,通过判断变量来停止线程。能适应大部分情况。
缺点:这个方法有一个潜在的大漏洞,就是若线程进入了阻塞状态,我们将不能通过修改volatile变量来停止线程
public class Tasks implements Runnable {
//增加关闭标记,注意内存可见性
private static volatile boolean stop = false;
@Override
public void run() {
while (!stop) {
System.out.println("执行线程中");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//测试
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Tasks());
thread.start();
Thread.sleep(1000);
stop = true;
}
}
3.使用中断(推荐)
通过 java 内定的机制响应中断:当线程调用 sleep(),wait() 方法后进入阻塞后,如果线程在阻塞的过程中被中断了,那么线程会捕获或抛出一个中断异常,我们可以根据这个中断异常去控制线程的停止。
这个可以避免堵塞无法关闭的情况。
/**
* 通过生产者消费者模式演示volatile的局限性,volatile不能唤醒已经阻塞的线程
* 生产者生产速度很快,消费者消费速度很慢,通过阻塞队列存储商品
*/
public class Demo8 {
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);//1s足够让生产者把阻塞队列塞满
Consumer consumer = new Consumer(storage);
while (consumer.needMoreNums()) {
System.out.println(storage.take() + "被消费");
Thread.sleep(100);//让消费者消费慢一点,给生产者生产的时间
}
System.out.println("消费者消费完毕");
// producer.canceled = true;//让生产者停止生产(实际情况是不行的,因为此时生产者处于阻塞状态,volatile不能唤醒阻塞状态的线程)
producerThread.interrupt();
}
}
class Producer implements Runnable {
public volatile boolean canceled = false;
private BlockingQueue storage;
public Producer(BlockingQueue storage) {
this.storage = storage;
}
@Override
public void run() {
int num = 0;
try {
while (num < Integer.MAX_VALUE / 2 && !Thread.currentThread().isInterrupted()) {
if (num % 100 == 0) {
this.storage.put(num);
System.out.println(num + "是100的倍数,已经被放入仓库");
}
num++;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("生产者停止生产");
}
}
}
class Consumer {
private BlockingQueue storage;
public Consumer(BlockingQueue storage) {
this.storage = storage;
}
public boolean needMoreNums() {
return Math.random() < 0.95 ? true : false;
}
← 多线程 为什么接口要实现Impl→