volatile到底能用来中断线程吗

在中断线程的方法中,除了使用interrupt(),还能否使用别的方法。volatile可以实现变量的可见性,能否用来充当中断标志位?

一、在没有阻塞的时候,可以使用volatile

设计一个实现Runnable的类,在run方法中循环打印出从0到100000中100的倍数。在循环判断的条件中,判断volatile的变量来控制是否停止循环。
在主线程中通过修改其volatile变量,是可以实现使线程停止的。

public class VolatileCanInterrupt implements Runnable {
    private volatile boolean canceled = false;  //volatile标志位
    @Override
    public void run() {
        int num = 0;
        try {
            while(num<=100000 && !canceled){
                if(num%100==0){
                    System.out.println(num+"是100的倍数");
                }
                num++;
                Thread.currentThread().sleep(1);
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        VolatileCanInterrupt volatileCanInterrupt = new VolatileCanInterrupt();
        Thread t = new Thread(volatileCanInterrupt);
        t.start();
        Thread.sleep(5000);	//等待五秒,然后停止计数线程
        volatileCanInterrupt.canceled = true;
    }
}

运行结果:
运行结果
可以看到在2600时线程停止,说明通过修改volatile变量成功地实现了停止线程。

二、在有阻塞的情况下,volatile不再适用

使用经典的生产者消费者问题来表示,通过一个BlockingQueue来存储商品。当满了之后生产者阻塞,等待消费者购买。然后在主线程中通知工厂应该停工了,来终止生产者线程。

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class VolatileError {
    public static void main(String[] args) throws InterruptedException {
        ArrayBlockingQueue storage = new ArrayBlockingQueue(10);
        Producer producer = new Producer(storage);
        Thread produceThread = new Thread(producer);
        produceThread.start();
        Thread.sleep(2000);
        Consumer consumer = new Consumer(storage);
        while(consumer.needMoreNums()){
            System.out.println(consumer.storage.take()+"被消费了");
            Thread.sleep(200);
        }
        System.out.println("消费者不需要商品了,工厂停工");
        producer.canceled = true;
    }
}
/**
 * 生产者线程类
 */
class Producer implements Runnable{
    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/100);
                    System.out.println("生产出第"+num/100+"件商品");
                }
                num++;
                Thread.currentThread().sleep(1);
            }
        }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;
    }
}

运行结果:
在这里插入图片描述
可以看到当消费者不需要商品,通知停工后,生产者依然在运行,只是在阻塞,所以无法检测到canceled的变化。

当使用interrupt(),线程会正常中断

使用正统的方法能不能在阻塞时中断线程呢?将上述对volatile变量的操作替换为对中断标志位的操作,使用interrupt()方法。
在这里插入图片描述
可以看到,生产者线程很完美的被中断了,所以,只有interrupt()才是正统的方法,它可以在线程阻塞的状态下去中断它

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值