线程的取消与关闭
在看《java并发编程实战》中的线程的取消和关闭中看到两个例子比较有趣,因此记录下来。
程序目的
想通过某种动作来达到取消某个特定线程的执行,从而达到中断改线程的目的
自定义标志位来控制线程的中断
书中先展示了一种反例,通过自定义标志位来控制线程的中断
- product
class Producer{
/**
* flag标志是否暂停生产
*/
private volatile Boolean flag = false;
/**
* 可阻塞的队列
*/
private BlockingQueue queue;
public Producer(BlockingQueue queue){
this.queue = queue;
}
/**
* 启动生产者
*/
public void run(){
try{
BigInteger p = BigInteger.ZERO;
while(!flag){
queue.put(p = p.nextProbablePrime());
System.out.println(Thread.currentThread().getName() + ":生产->" + p);
}
System.out.println(Thread.currentThread().getName() + ":生产停止");
}catch (InterruptedException e){
System.out.println(Thread.currentThread().getName() +":发生中断异常...");
}
}
/**
* 取消生产
*/
public void cancel(){
flag = true;
System.out.println(Thread.currentThread().getName()+":暂停");
}
}
通过volatile修饰flag标志位来控制生产者线程的取消
- main
BlockingQueue<BigInteger> queue = new ArrayBlockingQueue<BigInteger>(3);
Producer producer = new Producer(queue);
new Thread(()->{
producer.run();
},"生产者线程").start();
Thread.sleep(1000);
producer.cancel();
执行结果:
thread threadId
通过Arthas观察线程的执行情况,生产者线程状态为waiting,可以看到生产者线程在等待阻塞队列释放空间。由于生产者线程会一直等待阻塞队列的释放,所以并不能达到中断生产者线程的效果。
使用中断来进行取消
- product
class ProducerInterrupt{
/**
* 可阻塞的队列
*/
private BlockingQueue queue;
public ProducerInterrupt(BlockingQueue queue){
this.queue = queue;
}
/**
* 启动生产者
*/
public void run(){
try{
BigInteger p = BigInteger.ZERO;
while(!Thread.currentThread().isInterrupted()){
queue.put(p = p.nextProbablePrime());
System.out.println(Thread.currentThread().getName() + ":生产->" + p);
}
System.out.println(Thread.currentThread().getName() + ":生产停止");
}catch (InterruptedException e){
System.out.println(Thread.currentThread().getName() +":发生中断异常...");
}
}
}
- main
BlockingQueue<BigInteger> queue = new ArrayBlockingQueue<BigInteger>(3);
ProducerInterrupt producer = new ProducerInterrupt(queue);
Thread t1 = new Thread(()->{
producer.run();
},"生产者线程");
t1.start();
Thread.sleep(1000);
t1.interrupt();
执行结果:
总结:
在使用自定义的标志位来进行线程的取消操作时,要格外注意是否有会阻塞运行线程的操作,因为阻塞线程后会影响到使用volatile关键字来进行线程操作的判断逻辑。当存在有阻塞运行线程的操作时,会阻塞判断标志位的操作。