`
Technoboy
  • 浏览: 156741 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

Java Concurrent Programming (3)

    博客分类:
  • J2SE
阅读更多
3 线程异常
  线程在执行其run方法时,很有可能抛出异常。而run方法签名中,并未声明会抛出任何检查型异常。但在实际程序中,run方法中极其可能抛出一个异常,从而导致此线程被终止。更糟糕的是,如果线程因为异常终止,我们无法在主线程中使用try...catch...进行异常的捕获,从而可能导致一些问题的发生,例如无法释放某些资源等。主线程之所以不处理子线程抛出的RuntimeException,是因为线程是异步的,子线程没结束,主线程可能已经结束了。Thread类中的setUncaughtExceptionHandler就是处理线程中那些未捕获的异常,更明确的说,它处理那些未捕获的运行时异常。以下是一个例子,:
public class Dummy {
	
	public static void main(String[] args) {
		ThreadA threadA = null;
		ThreadB threadB = null;
		try {
			UncaughtException exe = new UncaughtException();
			threadA = new ThreadA();
			threadA.setName("threadA");
			threadA.setUncaughtExceptionHandler(exe);
			threadA.start();
			//threadA.run(); // exception thrown by common method can by caught in main thread
		} catch (Exception e) {
			System.out.println("catch RuntimeException e " + e.getMessage());
		}
		
		// main thread can not caught the exception thrown in ThreadB
		try {
			threadB = new ThreadB();
			threadB.start();
		} catch (Exception e) {
			System.out.println("catch RuntimeException e " + e.getMessage()); // not effect
		}
	}
}

class UncaughtException implements UncaughtExceptionHandler{

	@Override
	public void uncaughtException(Thread t, Throwable e) {
		System.out.println("thread " + t.getName() + " throws a uncaught excpetion " + e.getMessage());
		e.printStackTrace();
	}
	
}

class ThreadA extends Thread{
	
	public void run(){
		double a = 12 / 0;
	}
}

class ThreadB extends Thread{
	
	public void run(){
		try {
			double a = 12 / 0 ;
		} catch (ArithmeticException e) {
			throw e;
		}
	}
}

  程序的输出结果:
thread threadA throws a uncaught excpetion / by zero
java.lang.ArithmeticException: / by zero
	at org.java.test1.ThreadA.run(Dummy.java:40)
Exception in thread "Thread-1" java.lang.ArithmeticException: / by zero
	at org.java.test1.ThreadB.run(Dummy.java:48)

  线程内部的处理机制是这样子的:当一个线程突然间被一个无法捕获的异常终止时,首先这个线程本身会处理这个异常,由jvm调用dispatchUncaughtException方法,查看线程是否设置了异常处理方法,如果没有为此线程设置异常处理方法,此时线程会查看此线程所在线程组是否设置了线程异常处理方法,将异常处理交给线程组,然后ThreadGroup的uncaughtException方法会处理这个异常(也由jvm调用),在这个方法里,ThreadGroup会首先判断这个线程组是否还有父线程组,如果有父线程组,则继续交由父线程组处理这个异常,如果不存在父线程组,其会调用这个线程的默认异常处理方法,如果这个线程有默认的异常处理策略,则用这个默认的异常处理策略进行异常的处理,否则的话,会判断这个异常是否属于ThreadDeath类型(extends Error),如果这个异常属于ThreadDeath类型,则放弃处理,否则打印这个异常信息。
  同样,我们可以设置线程的默认异常处理策略,通过setDefaultUncaughtExceptionHandler即可,我们也可以通过调用getDefaultUncaughtExceptionHandler和getUncaughtExceptionHandler得到线程默认的异常处理程序信息和线程异常处理程序信息

3.1 InterruptedException异常
  Thread.sleep()、 Thread.join() 或 Object.wait()都可以抛出InterruptedException,它是一个检查异常(checked exception)。当一个线程在wait set中等待或者调用了sleep方法,而另一个线程调用了interrupt方法中断当前线程时,就会抛出InterruptedException。
当一个方法抛出InterruptedException,表示这个方法是一个阻塞方法。

3.2 阻塞方法
  阻塞的方法,不同于一般的普通方法。一般方法的完成只取决于它所要做的事情,以及是否有足够多可用的计算资源。而阻塞的方法还要取决于外部的一些事件,例如I/O完成,等待另一个线程释放对象锁等。一般方法在他们的工作做完后即可结束,而阻塞方法却不一定,其结束很难预测,因为他们还受外部因素的影响。
  阻塞方法可能因为等不到外部的事件而无法结束,那么让阻塞方法可取消就非常有用。可取消是指能从外部使之在正常结束工作前终止的操作。由Thread 提供并受 Thread.sleep()和Object.wait()支持的中断机制就是一种取消机制;它允许一个线程请求另一个线程停止它正在做的事情。当一个方法抛出 InterruptedException时,它是在告诉您,如果执行该方法的线程被中断,它将尝试停止它正在做的事情而提前返回,并通过抛出InterruptedException表明它提前返回。

3.3 处理InterruptedException异常
  如果一个方法抛出InterruptedException,表示这个方法为阻塞的方法,那么调用这个阻塞方法的方法也是一个阻塞方法。所以,我们必须有策略来处理InterruptedException异常。
  3.3.1 将InterruptedException异常传递给调用者
public class BoundQueue {
	//
	private static final int MAX_COUNT = 1000;
	
	private BlockingQueue<Message> queue = new LinkedBlockingQueue<Message>(MAX_COUNT);
	
	//
	public void put(Message msg) throws InterruptedException{
		queue.put(msg);
	}
	
	public Message take() throws InterruptedException{
		return queue.take();
	}
}

  3.3.2 在重新抛出InterruptedException异常前作特定的工作
      有时候,我们必须在抛出InterruptedException异常前,做一些特定的工作,例如:当一个游戏需要两个人同时加入才可以开始,如果一个人到来,程序在等待第二个人到来前中断,此时我们需要将第一个人放回到队列中,然后抛出InterruptedException异常警告,才不会让第一个的请求丢失。
public class MatcherPlayer {
	
	//
	private final PlayerQueue queue = new PlayerQueue(2);
	
	private PlayerSource source;
	
	private Game game;
	
	private Player one;
	
	private Player two;
	
	public MatcherPlayer(PlayerSource source){
		this.source = source;
	}
	
	public void matchPlayer() throws InterruptedException {
		try {
			while(true){
				one = source.waitForOne();
				two = source.waitForOne();
				game.start(one, two);
			}
		} catch (InterruptedException e) {
			if(one != null){
				queue.put(one);
			}
			throw e;
		}
	}
}

  3.3.3 捕捉 InterruptedException 后恢复中断状态
      有时候抛出 InterruptedException 并不合适,例如当由 Runnable 定义的任务调用一个可中断的方法时,就是如此。
public class TaskRunner implements Runnable {
	//
	private BlockingQueue<Message> queue;
	
	public TaskRunner(BlockingQueue<Message> queue){
		this.queue = queue;
	}
	
	public void run(){
		try {
			while(true){
				Message message = queue.take();
				message.execute();
			}
		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
		}
	}
}

  3.3.4 生吞中断
     处理InterruptedException时采取的最糟糕的做法是生吞它 —— 捕捉它,然后既不重新抛出它,也不重新断言线程的中断状态。对于不知如何处理的异常,最标准的处理方法是捕捉它,然后记录下它,但是这种方法仍然无异于生吞中断,因为调用栈中更高层的代码还是无法获得关于该异常的信息。
public class TaskRunnerBadly implements Runnable {
	//
	private BlockingQueue<Message> queue;
	
	public TaskRunnerBadly(BlockingQueue<Message> queue){
		this.queue = queue;
	}
	
	public void run(){
		try {
			while(true){
				Message message = queue.take();
				message.execute();
			}
		} catch (InterruptedException e) {
			// NOP
		}
	}
}

3.4 不可中断的阻塞方法
  并非所有的阻塞方法都抛出 InterruptedException。输入和输出流类会阻塞等待 I/O 完成,但是它们不抛出 InterruptedException,而且在被中断的情况下也不会提前返回。然而,对于套接字 I/O,如果一个线程关闭套接字,则那个套接字上的阻塞 I/O 操作将提前结束,并抛出一个 SocketException。java.nio 中的非阻塞 I/O 类也不支持可中断 I/O,但是同样可以通过关闭通道或者请求 Selector 上的唤醒来取消阻塞操作。类似地,尝试获取一个内部锁的操作(进入一个 synchronized 块)是不能被中断的,但是 ReentrantLock 支持可中断的获取模式。
5
4
分享到:
评论
3 楼 悲剧了 2011-11-19  
good,这块一直没怎么闹明白,顺便问下这个是自己写的还是翻译的那本java 并发编程?
2 楼 Technoboy 2011-05-11  
Summer花的姿态 写道
  

1 楼 Summer花的姿态 2011-05-10  
  

相关推荐

    Java Concurrent Programming

    为了简化多线程编程,Java提供了一系列工具和API,如`java.util.Timer`和`java.util.concurrent`包,这些工具可以帮助开发者更高效地管理线程间的同步问题。 ##### 1.2 synchronized关键字 `synchronized`关键字是...

    concurrent programming in java design principles and patterns .chm

    concurrent programming in java design principles and patterns .chm

    Concurrent Programming in Java

    3. **高级并发工具**:随着Java 5的发布,`java.util.concurrent`包引入了许多高级并发工具,如`ExecutorService`、`Future`、`Semaphore`、`CyclicBarrier`和`CountDownLatch`等。这些工具简化了并发代码的编写,...

    JAVA Concurrent Programming

    3. `java.util.concurrent.atomic`包 这个包提供了原子变量类,如`AtomicInteger`、`AtomicLong`等,它们支持无锁的线程安全操作,可以在不使用`synchronized`的情况下保证变量的原子性更新,从而降低锁的使用,提高...

    Doug Lea, Concurrent Programming in Java Design Principles and Patterns

    《Doug Lea, Concurrent Programming in Java Design Principles and Patterns》是一本深入探讨Java并发编程的经典著作,由Doug Lea撰写。这本书对于理解Java平台上的多线程编程和并发设计模式至关重要,是许多Java...

    使用Java并发编程Concurrent Programming Using Java

    Java平台提供了丰富的API支持并发编程,如`java.util.concurrent`包下的各种类和接口,这些工具可以帮助开发者更高效地管理多线程环境下的任务调度和数据共享问题。 ### Java并发编程基础 #### 1. 多线程基础 - **...

    concurrent programming in java(doug lea)

    《Java并发编程》一书是由著名并发编程专家Doug Lea所著,他同时也是Java并发包(JUC)的作者,这本书详细介绍了Java多线程编程的基础概念和高级技术。 首先,书中提到了并发编程的基本概念,包括并发模型、设计力...

    Concurrent Programming in Java™: Design Principles and Patterns 2nd

    本书《Concurrent Programming in Java™: Design Principles and Patterns 2nd》由Doug Lea编写,出版于1999年,是关于Java并发编程的一本权威指南。Java平台因其强大的线程支持能力而备受青睐,这使得Java程序员...

    Concurrent Programming on Windows 无水印pdf

    Concurrent Programming on Windows 英文无水印pdf pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系...

    Learning Concurrent Programming in Scala, 2nd Edition

    Title: Learning Concurrent Programming in Scala, 2nd Edition Author: Aleksandar Prokopec Length: 382 pages Edition: 2nd Revised edition Language: English Publisher: Packt Publishing - ebooks Account ...

    Concurrent Programming in Java™: Design Principles and Patterns, Second Edition

    Concurrent Programming in Java™: Design Principles and Patterns, Second Edition. 介绍并发编程的好的著作,著名的并发大师 Doug Lea的杰作。

    word版本

    3. **创建线程**:这一章节讨论如何建立和管理并发,使用Thread对象。内容包括线程的创建、启动、协作以及线程安全的实现策略。 每一章都包含一系列独立主题的主节,分别介绍高层次的设计原则、构造的技术细节、...

    Java并发编程:设计原则与模式(Concurrent.Programming.in.Java)(中英版)

    例如,使用无锁数据结构或原子操作(`java.util.concurrent.atomic`包)。 3. **避免死锁、活锁和饥饿**:理解并预防这些并发问题至关重要。死锁发生在两个或多个线程相互等待对方释放资源导致僵局;活锁是线程不断...

    Concurrent Programming in Java Design Principles and Pattern

    Concurrent Programming in Java Design Principles and Pattern英文版 2.48M Java并发编程设计原则与模式_第二版(原书中文版) 19.4M Concurrent_Programming_in_Java_Design_Principles_Lecture DougLea

    Concurrent - Programming in Java.pdf

    - **标准库**:Java并发工具包(java.util.concurrent)提供了丰富的并发工具类。 - **第三方库**:例如Apache Commons Concurrency等。 ##### 2. 构建库 - **自定义并发组件**:根据项目需求开发特定的并发工具。 ...

    Concepts and Notations for Concurrent Programming

    《Concepts and Notations for Concurrent Programming》这篇论文由Gregory R. Andrews和Fred B. Schneider撰写,深入探讨了并行编程的核心概念和技术。尽管这是一篇较为古老的文章,但其内容仍然具有很高的参考价值...

    java concurrent source code

    资深Java专家10年经验总结,全程案例式讲解,首本全面介绍Java多线程编程技术的专著 结合大量实例,全面讲解Java多线程编程中的并发访问、线程间通信、锁等最难突破的核心技术与应用实践 封底 Java多线程无处不在,...

Global site tag (gtag.js) - Google Analytics