`
臻是二哥
  • 浏览: 183400 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
博客专栏
Group-logo
Java技术分享
浏览量:0
社区版块
存档分类
最新评论

JAVA并发-中断处理和任务取消

阅读更多
中断处理
在java程序中,当使用Thread.sleep()或者BlockingQueue.take()等阻塞方法时,需要处理InterruptedException。对于这种异常,通常有2种方案进行处理。
1. 传递异常:将异常传递给方法的调用者。示例如下:
BlockingQueue<String> queue;
public String getNextString() throws InterruptedException{
		return queue.take();
} 

2. 恢复异常:在大多数情况下,异常是可以传递的,但有些情况是无法传递异常的,比如在Runnable的run()方法中,我们不可以抛出异常。此时需要我们恢复异常,这样在调用栈中更高层次的代码将看到引发了一个中断。示例如下:
BlockingQueue<String> queue;
public String getNextString() throws InterruptedException{
		String result=null;
     try{
			result=queue.take();
}catch(InterruptedException e){
	Thead.currentThread.interrupt();
}finally{
	Return result;
}
} 

以上是处理InterruptedException的常用方法,对于InterruptedException,千万不要捕获异常但不做任何处理。当我们使用中断来结束线程时,在catch块中也可以使用interrupted()来清除异常。

任务取消
多线程编程时,有时候需要取消某些任务线程,有以下3种方案:
1. 设定一个线程取消的标记,任务线程定期的检查这个标记。示例如下:
class Task implements Runnable{
	private volatile boolean cancel=false;
	@Override
	public void run() {
		while(!cancel){
			System.out.println("...");
		}
	}
	public void cancel(){
		cancel=true;
	}
}
2. 上面的示例描述的是最一般的场景,试想一下,如果while(!cancel)循环中调用了一个阻塞的方法,那么有这样一种可能:程序可能阻塞在某个方法中。示例如下:
class Task implements Runnable{
	private volatile boolean cancel=false;
	private BlockingQueue<String> blockingQueue;
	public Task(BlockingQueue<String> queue){
		this.blockingQueue=queue;
	}
	@Override
	public void run() {
		try{
			while(!cancel){
				System.out.println("...");
				this.blockingQueue.take();//当程序阻塞在此处时,即便cancel被更新了,也无法感知,这种情况下,程序永远无法退出。
			}			
		}catch(InterruptedException e){
			Thread.currentThread().interrupt();
		}
	}
	public void cancel(){
		cancel=true;
	}
}

当while(!cancel)循环中调用了一个阻塞的方法时,使用标记位的方式终止程序就不再使用了,此时使用中断的方式退出程序:

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class CDemo {
        public static void main(String [] args) throws Exception{
        	BlockingQueue<String> b=new ArrayBlockingQueue<String>(3);
        	b.put("a");
        	b.put("ab");
        	b.put("abc");
        	
        	Task task=new Task(b);
        	task.start();
        	Thread.sleep(4000);
        	
        	task.cancel();
        }
}

class Task extends Thread{  
    private BlockingQueue<String> blockingQueue;  
    public Task(BlockingQueue<String> queue){  
        this.blockingQueue=queue;  
    }  
    @Override  
    public void run() {  
        try{  
        	while(true){
//        		if(Thread.currentThread().isInterrupted()) //一定注意,这行是错误做法
        		if(interrupted())//判断当前线程是否被中断
        			break;
                String str=this.blockingQueue.take(); 
                System.out.println(str);
            }  
        }catch(InterruptedException e){  
            //Thread.currentThread().interrupt();  
        	interrupted();//清除中断痕迹
        }finally{
        	System.out.println("线程结束!");
        }
    }  
    public void cancel(){  
        this.interrupt();//中断当前线程
//    	Thread.currentThread().interrupt(); //一定注意,这行是错误做法
    }  
}  


3. 在生产者消费者问题中,使用“毒丸对象”来终止消费者线程。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;

public class Coordinator {
	public static final Object POISON_PILL = new Object();//special object to kill consumers
	private int productCount = 1;
	private int consumerCount = 3;

	public void startAll() throws Exception{
		BlockingQueue<Object> queue = new ArrayBlockingQueue<Object>(5);
		CountDownLatch activeProductorNum = new CountDownLatch(productCount);
		CountDownLatch activeConsumerNum = new CountDownLatch(consumerCount);

		for(int i = 0; i < consumerCount; i++){
			new Thread(new Consumer("consumer " + i, queue,activeConsumerNum)).start();
		}

		for(int i = 0; i < productCount; i++){
			new Thread(new Producer("producer " + i, queue, activeProductorNum)).start();
		}
		
		activeProductorNum.await();//等待所有生产者生产结束
		System.out.println("All producer finished, putting POISON_PILL to the queue to stop consumers!");
		queue.put(POISON_PILL);
		
		activeConsumerNum.await();//等待所有生产者生产结束
		System.out.println("All consumer finished!");
	}
	
	public static void main(String[] args) throws Exception{
		new Coordinator().startAll();
	}
}

class Producer implements Runnable {
	private String name;
	private BlockingQueue<Object> queue;
	private CountDownLatch activeProducerNum;
	
	public Producer(String name, BlockingQueue<Object> queue, CountDownLatch activeProducerNum){
		this.name = name;
		this.queue = queue;
		this.activeProducerNum=activeProducerNum;
	}

	@Override
	public void run() {
		try {
			for(int i=0;i<10;i++){
				queue.put(i);
				System.out.println(name + " produced "+i);				
			}
				
		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
		} finally{
			System.out.println(name + " finished.");
			activeProducerNum.countDown();
		}
	}
}


class Consumer implements Runnable {
	private String name;
	private BlockingQueue<Object> queue;
	private CountDownLatch activeConsumerNum;

	public Consumer(String name, BlockingQueue<Object> queue,CountDownLatch activeConsumerNum){
		this.name = name;
		this.queue = queue;
		this.activeConsumerNum=activeConsumerNum;
	}

	@Override
	public void run() {
		try {
			while (true) {
				Object item = queue.take();
				if (item == Coordinator.POISON_PILL) {
					queue.put(item);//放回继续毒害其他消费者
					break;
				}
				System.out.println(name + " consumed "+item);
			}
		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
		} finally{
			System.out.println(name + " finished");
			activeConsumerNum.countDown();
		}
	}
}






0
2
分享到:
评论

相关推荐

    Java并发编程实战

    1.2.3 异步事件的简化处理 1.2.4 响应更灵敏的用户界面 1.3 线程带来的风险 1.3.1 安全性问题 1.3.2 活跃性问题 1.3.3 性能问题 1.4 线程无处不在 第一部分 基础知识 第2章 线程安全性 2.1 什么是线程安全...

    Java并发编程实践 PDF 高清版

    7.1 任务取消 7.2 停止基于线程的服务 7.3 处理反常的线程终止 7.4 JVM关闭 第8章 应用线程池 8.1 任务与执行策略问的隐性耦合 8.2 定制线程池的大小 8.3 配置ThreadPoolExecutor 8.4 扩展ThreadPoolExecutor 8.5 ...

    Java 并发编程实战

    1.2.3 异步事件的简化处理 1.2.4 响应更灵敏的用户界面 1.3 线程带来的风险 1.3.1 安全性问题 1.3.2 活跃性问题 1.3.3 性能问题 1.4 线程无处不在 第一部分 基础知识 第2章 线程安全性 2.1 什么是线程安全...

    JAVA并发编程实践_中文版(1-16章全)_1/4

    7.1 任务取消 7.2 停止基于线程的服务 7.3 处理反常的线程终止 7.4 jvm关闭 第8章 应用线程池 8.1 任务与执行策略问的隐性耦合 8.2 定制线程池的大小 8.3 配置threadpoolexecutor 8.4 扩展threadpoolexecutor 8.5 ...

    Java 7并发编程实战手册

    java7在并发编程方面,带来了很多令人激动的新功能,这将使你的应用程序具备更好的并行任务性能。 《Java 7并发编程实战手册》是Java 7并发编程的实战指南,介绍了Java 7并发API中大部分重要而有用的机制。全书分为9...

    Java并发编程(学习笔记).xmind

    任务取消 停止基于线程的服务 处理非正常的线程终止 JVM关闭 线程池的定制化使用 任务和执行策略之间的隐性耦合 线程池的大小 配置ThreadPoolExecutor(自定义的线程池) 此处需要注意...

    Java并发编程part2

    中文完整版的Java并发编程实践PDF电子书 作者:Brian Gogetz Tim Peierls Joshua Bloch Joseph Bowbeer David Holmes Doug Lea 译者:韩锴 方秒 目录 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的优点 1.3 ...

    Java并发编程实践part1

    中文完整版的Java并发编程实践PDF电子书 作者:Brian Gogetz Tim Peierls Joshua Bloch Joseph Bowbeer David Holmes Doug Lea 译者:韩锴 方秒 目录 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的优点 1.3 ...

    并发编程实践,全面介绍基础知识、JVM同步原语、线程安全、低级并发工具、线程安全容器、高级线程协作工具、Executor部分等

    详细介绍java并发编程相关知识: 基础知识   并发与并行   Java并发演进历史   Java并发模型   线程模型   存储模型 JVM同步原语 volatile CAS ...  保护“共享数据” ...  线程的中断与任务的取消   其他

    Android异步并发类库Android-lite-go.zip

    可定义等待队列满载后处理新请求的策略:抛弃队列中最新的任务抛弃队列中最旧的任务抛弃当前新任务直接执行(阻塞当前线程)抛出异常(中断当前线程)LiteGo 使用初始化:// 智能并发调度控制器:设置[最大并发数]...

    Visual C#2010 从入门到精通(Visual.C#.2010.Step.By.Step).完整去密码锁定版 I部分

    27.4 取消任务和处理异常 578 27.4.1 协作式取消的原理 578 27.4.2 使用aggregateexception类处理任务异常 586 27.4.3 为canceled和faulted任务使用延续任务 589 第27章快速参考 590 第28章 执行并行数据访问 ...

    IIS6.0 IIS,互联网信息服务

    最初是Windows NT版本的可选包,随后内置在Windows 2000、Windows XP Professional和Windows Server 2003一起发行,但在普遍使用的Windows XP Home版本上并没有IIS。 添加和运行准备  一、IIS的添加 请进入“控制...

    javaSE代码实例

    第16章 多线程——Java中的并发协作 343 16.1 线程的基本知识 343 16.1.1 多线程编程的意义 343 16.1.2 定义自己的线程 344 16.1.3 创建线程对象 345 16.1.4 启动线程 347 16.1.5 同时使用多个线程 ...

Global site tag (gtag.js) - Google Analytics