Java并发(一)

定义任务

使用Runnable接口编写run()方法,在run()中静态方法Thread.yield()的调用时对线程调度器的一种建议,可以将CPU从一个线程转义给另一线程。Runnable对象把自己提交给Thread构造器,调用Thread对象的start()方法为该线程执行初始化操作,然后调用Runnable的run()方法,以便在新线程中启动该任务。


代码1-1

public class LiftOff implements Runnable {

	protected int countDown = 10;
	private static int taskCount = 0;
	private final int id = taskCount++;

	public LiftOff() {
		super();
		// TODO Auto-generated constructor stub
	}

	public LiftOff(int countDown) {
		super();
		this.countDown = countDown;
	}

	public String status() {
		return "#" + id + "(" + (countDown > 0 ? countDown : "Liftoff!") + ")   ";
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (countDown-- > 0) {
			System.out.print(status());
			Thread.yield();
		}
	}

	public static void main(String[] args) {
		<pre name="code" class="java"><span style="white-space:pre">		</span>for (int i = 0; i < 5; i++) {
			new Thread(new LiftOff()).start();
		}
		System.out.println("Waiting for LiftOff");
}}
 


 
 

代码1-1运行结果:

Waiting for LiftOff
#2(9)   #1(9)   #3(9)   #0(9)   #4(9)   #0(8)   #3(8)   #1(8)   #2(8)   #1(7)   #3(7)   #0(7)   #4(8)   #0(6)   #3(6)   #1(6)   #2(7)   #1(5)   #3(5)   #0(5)   #4(7)   #0(4)   #3(4)   #1(4)   #2(6)   #1(3)   #3(3)   #3(2)   #3(1)   #3(Liftoff!)   #0(3)   #4(6)   #0(2)   #1(2)   #2(5)   #1(1)   #1(Liftoff!)   #0(1)   #4(5)   #4(4)   #0(Liftoff!)   #2(4)   #4(3)   #2(3)   #2(2)   #2(1)   #2(Liftoff!)   #4(2)   #4(1)   #4(Liftoff!)   


由运行结果可见,start()方法的调用迅速返回,然后打印Waiting for LiftOff,接着执行各个线程的run()方法。


使用Executors

java.util.concurrent包中的执行器Executors(java.util.concurrent.Executors)可以管理Thread对象。Executors允许管理异步任务的执行,而无须显示地管理线程的生命周期

代码1-2

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CachedThreadPool {

	public static void main(String[] args) {
		ExecutorService exec = Executors.newCachedThreadPool();
		for (int i = 0; i < 5; i++) {
			exec.execute(new LiftOff());
		}
		exec.shutdown();
	}

}


代码1-2运行结果:

#0(9)   #2(9)   #2(8)   #4(9)   #3(9)   #3(8)   #1(9)   #3(7)   #3(6)   #4(8)   #4(7)   #2(7)   #0(8)   #0(7)   #2(6)   #2(5)   #4(6)   #4(5)   #3(5)   #1(8)   #1(7)   #1(6)   #3(4)   #3(3)   #4(4)   #4(3)   #2(4)   #2(3)   #0(6)   #2(2)   #2(1)   #4(2)   #4(1)   #3(2)   #1(5)   #1(4)   #1(3)   #3(1)   #3(Liftoff!)   #4(Liftoff!)   #2(Liftoff!)   #0(5)   #1(2)   #0(4)   #1(1)   #1(Liftoff!)   #0(3)   #0(2)   #0(1)   #0(Liftoff!)   



ExecutorService(具有服务生命周期的Executors)知道如何构建上下文来执行Runnable对象,shutdown()方法的调用可以防止新任务被提交给Executors


FixedThreadPool可以预先执行代价高昂的线程分配,即可以限制线程数量。这样就不用为每个任务都固定地付出创建线程的开销了。

代码1-3

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FixedThreadPool {
	
	public static void main(String[] args) {
		ExecutorService exec = Executors.newFixedThreadPool(3);
		for (int i = 0; i < 5; i++) {
			exec.execute(new LiftOff());
		}
		exec.shutdown();
	}

}


代码1-3运行结果:

#0(9)   #2(9)   #1(9)   #0(8)   #2(8)   #0(7)   #1(8)   #0(6)   #2(7)   #0(5)   #1(7)   #0(4)   #2(6)   #0(3)   #1(6)   #0(2)   #2(5)   #0(1)   #1(5)   #0(Liftoff!)   #2(4)   #1(4)   #3(9)   #2(3)   #3(8)   #1(3)   #3(7)   #2(2)   #3(6)   #1(2)   #3(5)   #2(1)   #3(4)   #1(1)   #3(3)   #2(Liftoff!)   #3(2)   #4(9)   #1(Liftoff!)   #4(8)   #3(1)   #4(7)   #3(Liftoff!)   #4(6)   #4(5)   #4(4)   #4(3)   #4(2)   #4(1)   #4(Liftoff!)   


SingleThreadExecutor可以连续运行一个线程,如果 SingleThreadExecutor提交任务,这些任务将排队,每个任务在下一个任务开始之前运行结束,所有的任务都将使用相同的线程

代码1-4

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SingleThreadExecutor {
	
	public static void main(String[] args) {
		ExecutorService exec = Executors.newSingleThreadExecutor();
		for (int i = 0; i < 5; i++) {
			exec.execute(new LiftOff());
		}
		exec.shutdown();
	}

}

代码1-4运行结果:

#0(9)   #0(8)   #0(7)   #0(6)   #0(5)   #0(4)   #0(3)   #0(2)   #0(1)   #0(Liftoff!)   #1(9)   #1(8)   #1(7)   #1(6)   #1(5)   #1(4)   #1(3)   #1(2)   #1(1)   #1(Liftoff!)   #2(9)   #2(8)   #2(7)   #2(6)   #2(5)   #2(4)   #2(3)   #2(2)   #2(1)   #2(Liftoff!)   #3(9)   #3(8)   #3(7)   #3(6)   #3(5)   #3(4)   #3(3)   #3(2)   #3(1)   #3(Liftoff!)   #4(9)   #4(8)   #4(7)   #4(6)   #4(5)   #4(4)   #4(3)   #4(2)   #4(1)   #4(Liftoff!)   

从任务中产生返回值

Runnable不返回任何值,如果希望任务完成时能够返回一个值,可以使用Callable接口,Callable接口是一种具有类型参数的泛型,它的类型参数表示是从方法call()中返回的值,并且必须使用ExecutorService.submit()调用它

代码1-5

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class TaskWithResult implements Callable<String> {

	private int id;

	public TaskWithResult(int id) {
		super();
		this.id = id;
	}

	@Override
	public String call() throws Exception {
		// TODO Auto-generated method stub
		return "result of TaskWithResult " + id;
	}

	public static void main(String[] args) {
		ExecutorService exec = Executors.newCachedThreadPool();
		List<Future<String>> res = new ArrayList<Future<String>>();
		for (int i = 0; i < 9; i++) {
			res.add(exec.submit(new TaskWithResult(i)));
		}
		for (Future<String> fs : res) {
			try {
				System.out.println(fs.get());
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ExecutionException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				exec.shutdown();
			}
		}
	}

}


代码1-5运行结果:

result of TaskWithResult 0
result of TaskWithResult 1
result of TaskWithResult 2
result of TaskWithResult 3
result of TaskWithResult 4
result of TaskWithResult 5
result of TaskWithResult 6
result of TaskWithResult 7
result of TaskWithResult 8


休眠

使用sleep()方法阻塞线程

代码1-6

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class SleepingTask extends LiftOff {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (countDown-- > 0) {
			try {
				System.out.print(status());
				TimeUnit.MILLISECONDS.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		ExecutorService exec = Executors.newCachedThreadPool();
		for (int i = 0; i < 5; i++) {
			exec.execute(new SleepingTask());
		}
		exec.shutdown();
	}
}

代码1-6运行结果:

#1(9)   #2(9)   #4(9)   #0(9)   #3(9)   #3(8)   #1(8)   #2(8)   #4(8)   #0(8)   #4(7)   #2(7)   #0(7)   #3(7)   #1(7)   #2(6)   #4(6)   #3(6)   #0(6)   #1(6)   #2(5)   #4(5)   #3(5)   #0(5)   #1(5)   #4(4)   #2(4)   #0(4)   #1(4)   #3(4)   #2(3)   #4(3)   #1(3)   #0(3)   #3(3)   #2(2)   #4(2)   #3(2)   #1(2)   #0(2)   #4(1)   #2(1)   #3(1)   #0(1)   #1(1)   #4(Liftoff!)   #2(Liftoff!)   #3(Liftoff!)   #0(Liftoff!)   #1(Liftoff!)   


优先级

尽管CPI处理线程集的顺序是不确定的,但调度器更倾向于优先级高的线程,然而这并不意味着优先级低的线程得不到执行。可以用Thread.currentThread().getPriority()获取当前线程的优先级,也可以用Thread.currentThread().setPriority()来修改优先级

代码1-7

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SimplePriorities implements Runnable {
	protected int countDown = 5;
	private double d = 0;
	private int priority;

	public SimplePriorities(int priority) {
		super();
		this.priority = priority;
	}

	@Override
	public String toString() {
		return Thread.currentThread() + ":" + countDown;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		Thread.currentThread().setPriority(priority);
		while (true) {
			for (int i = 1; i < 100000; i++) {
				d += (Math.PI + Math.E) / (double) i;
				if (i % 1000 == 0) {
					Thread.yield();
				}
			}
			System.out.println(this);
			if (--countDown == 0) {
				return;
			}
		}
	}

	public static void main(String[] args) {
		ExecutorService exec = Executors.newCachedThreadPool();
		for (int i = 0; i < 3; i++) {
			exec.execute(new SimplePriorities(Thread.MIN_PRIORITY));
			exec.execute(new SimplePriorities(Thread.MAX_PRIORITY));
		}
		exec.shutdown();
	}
}

 代码1-7运行结果: 

Thread[pool-1-thread-6,10,main]:5Thread[pool-1-thread-2,10,main]:5Thread[pool-1-thread-4,10,main]:5Thread[pool-1-thread-3,1,main]:5Thread[pool-1-thread-1,1,main]:5Thread[pool-1-thread-5,1,main]:5Thread[pool-1-thread-4,10,main]:4Thread[pool-1-thread-1,1,main]:4Thread[pool-1-thread-6,10,main]:4Thread[pool-1-thread-2,10,main]:4Thread[pool-1-thread-3,1,main]:4Thread[pool-1-thread-5,1,main]:4Thread[pool-1-thread-4,10,main]:3Thread[pool-1-thread-1,1,main]:3Thread[pool-1-thread-6,10,main]:3Thread[pool-1-thread-2,10,main]:3Thread[pool-1-thread-3,1,main]:3Thread[pool-1-thread-1,1,main]:2Thread[pool-1-thread-5,1,main]:3Thread[pool-1-thread-3,1,main]:2Thread[pool-1-thread-4,10,main]:2Thread[pool-1-thread-6,10,main]:2Thread[pool-1-thread-2,10,main]:2Thread[pool-1-thread-3,1,main]:1Thread[pool-1-thread-4,10,main]:1Thread[pool-1-thread-1,1,main]:1Thread[pool-1-thread-5,1,main]:2Thread[pool-1-thread-2,10,main]:1Thread[pool-1-thread-6,10,main]:1Thread[pool-1-thread-5,1,main]:1

run()中执行了100000次开销相当大的浮点运算,变量d是volatile的,以确保不被编译器进行优化

后台线程

后台线程,是指在程序运行的时候在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分。当所有的非后台线程结束时,程序也就终止了,同事会杀死进程中所有的后台线程。反过来说,只要有任何非后台线程还在运行,程序就不会终止。main()就是一个非后台线程

代码1-8

import java.util.concurrent.TimeUnit;

public class SimpleDaemons implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			while (true) {
				TimeUnit.MILLISECONDS.sleep(100);
				System.out.println(Thread.currentThread() + " " + this);
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) throws Exception {
		for(int i=0;i<10;i++){
			Thread daemon = new Thread(new SimpleDaemons());
			daemon.setDaemon(true);
			daemon.start();
		}
		System.out.println("All ademons started");
		TimeUnit.MILLISECONDS.sleep(175);
	}

}


代码1-8运行结果:

All ademons started
Thread[Thread-9,5,main] com.jerry.demo1.SimpleDaemons@3bc473
Thread[Thread-6,5,main] com.jerry.demo1.SimpleDaemons@384065
Thread[Thread-3,5,main] com.jerry.demo1.SimpleDaemons@3dc0bb
Thread[Thread-0,5,main] com.jerry.demo1.SimpleDaemons@1de9ac4
Thread[Thread-4,5,main] com.jerry.demo1.SimpleDaemons@c79809
Thread[Thread-1,5,main] com.jerry.demo1.SimpleDaemons@1ce784b
Thread[Thread-2,5,main] com.jerry.demo1.SimpleDaemons@1c5fde0
Thread[Thread-7,5,main] com.jerry.demo1.SimpleDaemons@194d372
Thread[Thread-8,5,main] com.jerry.demo1.SimpleDaemons@10bbf9e
Thread[Thread-5,5,main] com.jerry.demo1.SimpleDaemons@513d61


必须在线程启动之前先调用setDaemon()方法,才能把它设置为后台线程

DaemonThreadFactory可以将后台状态设置为true,现在可以用DaemonThreadFactory作为参数传递给Executors.newCachedThreadPool()

代码1-6

import java.util.concurrent.ThreadFactory;

public class DaemonThreadFactory implements ThreadFactory {

	@Override
	public Thread newThread(Runnable r) {
		// TODO Auto-generated method stub
		Thread t = new Thread(r);
		t.setDaemon(true);
		return t;
	}

}

代码1-7

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class DaemonFromFactory implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			try {
				TimeUnit.MILLISECONDS.sleep(100);
				System.out.println(Thread.currentThread()+" "+this);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		ExecutorService exec = Executors.newCachedThreadPool(new DaemonThreadFactory());
		for(int i=0;i<9;i++){
			exec.execute(new DaemonFromFactory());
		}
		System.out.println("All daemons started");
		TimeUnit.MILLISECONDS.sleep(200);
	}

}

代码1-7运行结果:

result of TaskWithResult 0
result of TaskWithResult 1
result of TaskWithResult 2
result of TaskWithResult 3
result of TaskWithResult 4
result of TaskWithResult 5
result of TaskWithResult 6
result of TaskWithResult 7
result of TaskWithResult 8


可以通过isDaemon()方法确定线程是否是后台线程,如果是后台线程,那它创建的任何线程都将被自动设置为后台线程

如代码1-8

<pre name="code" class="java">import java.util.concurrent.TimeUnit;

class Daemon implements Runnable {
	private Thread[] t = new Thread[10];

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for (int i = 0; i < t.length; i++) {
			t[i] = new Thread(new DaemonSpawn());
			t[i].start();
			System.out.print("DaemonSpawn " + i + " started, ");
		}
		for (int i = 0; i < t.length; i++) {
			System.out.print("t[" + i + "].isDaemon() = " + t[i].isDaemon() + ",  ");
		}
		while (true) {
			Thread.yield();
		}
	}

}

class DaemonSpawn implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			Thread.yield();
		}
	}

}

public class Daemons {
	public static void main(String[] args) throws InterruptedException {
		Thread d = new Thread(new Daemon());
		d.setDaemon(true);
		d.start();
		System.out.print("d.isDaemon() = " + d.isDaemon() + ",  ");
		TimeUnit.MILLISECONDS.sleep(1);
	}
}

 代码1-8运行结果: 

d.isDaemon() = true,  DaemonSpawn 0 started, DaemonSpawn 1 started, DaemonSpawn 2 started, DaemonSpawn 3 started, DaemonSpawn 4 started, DaemonSpawn 5 started, DaemonSpawn 6 started, DaemonSpawn 7 started, DaemonSpawn 8 started, DaemonSpawn 9 started, t[0].isDaemon() = true,  t[1].isDaemon() = true,  t[2].isDaemon() = true,  t[3].isDaemon() = true,  t[4].isDaemon() = true,  t[5].isDaemon() = true,  t[6].isDaemon() = true,  t[7].isDaemon() = true,  t[8].isDaemon() = true,  t[9].isDaemon() = true,  

编码的变体

可以继承Thread实现多线程

代码1-9

public class SimpleThread extends Thread {

	private int countDown = 5;
	private static int threadCount = 0;

	public SimpleThread() {
		super(Integer.toString(++threadCount));
		start();
	}

	@Override
	public String toString() {
		return "#" + getName() + "(" + countDown + "),  ";
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			System.out.print(this);
			if (--countDown == 0) {
				return;
			}
		}
	}

	public static void main(String[] args) {
		for (int i = 0; i < 6; i++) {
			new SimpleThread();
		}
	}
}


代码1-9运行结果:
#2(5),  #4(5),  #5(5),  #3(5),  #3(4),  #3(3),  #3(2),  #1(5),  #3(1),  #6(5),  #5(4),  #4(4),  #2(4),  #2(3),  #4(3),  #5(3),  #5(2),  #6(4),  #1(4),  #1(3),  #1(2),  #6(3),  #6(2),  #5(1),  #4(2),  #2(2),  #2(1),  #4(1),  #6(1),  #1(1),  


可以调用Thread(String name)构造器为Thread对象赋予具体的名称,名称可以从getName()获得

自管理Runnable

代码1-10

public class SelfManaged implements Runnable {
	private int countDown = 5;
	private Thread t = new Thread(this);

	public SelfManaged() {
		super();
		// TODO Auto-generated constructor stub
		t.start();
	}

	@Override
	public String toString() {
		return Thread.currentThread().getName() + "(" + countDown + "),  ";
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			System.out.print(this);
			if (--countDown == 0) {
				return;
			}
		}
	}

	public static void main(String[] args) {
		for (int i = 0; i < 5; i++) {
			new SelfManaged();
		}
	}
}

代码1-10运行结果:

Thread-1(5),  Thread-3(5),  Thread-2(5),  Thread-0(5),  Thread-2(4),  Thread-3(4),  Thread-3(3),  Thread-1(4),  Thread-4(5),  Thread-4(4),  Thread-1(3),  Thread-3(2),  Thread-3(1),  Thread-2(3),  Thread-0(4),  Thread-2(2),  Thread-1(2),  Thread-1(1),  Thread-4(3),  Thread-4(2),  Thread-2(1),  Thread-0(3),  Thread-0(2),  Thread-4(1),  Thread-0(1),  


加入一个线程

一个线程可以在其他线程上调用join方法,其效果是等待一段时间直到第二个线程结束才继续执行。如果某个线程在另一个线程t上调用t.join(),此线程被挂起,直到目标线程t结束才恢复,也可以在调用join()时带上一个超时参数,这样如果目标线程在这段时间还没结束的话,join()方法总能返回,join()方法的调用可以被中断,做法是在调用线程上调用interrupt()方法,需要用到try-catch

代码1-11

<pre name="code" class="java"><pre name="code" class="java">class Sleeper extends Thread {

	private int duration;

	public Sleeper(String name, int sleepTime) {
		super(name);
		this.duration = sleepTime;
		start();
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			sleep(duration);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			System.out.println(getName() + " was interrupted. " + "isInterrupted(): " + isInterrupted());
			return;
		}
		System.out.println(getName() + " has awkened");
	}
}

class Joiner extends Thread {
	private Sleeper sleeper;

	public Joiner(String name, Sleeper sleeper) {
		super(name);
		this.sleeper = sleeper;
		start();
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			sleeper.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			System.out.println("Interrupted");
		}
		System.out.println(getName() + " join completed");
	}

}

public class Joining {
	public static void main(String[] args) {
		Sleeper sleepey = new Sleeper("Sleepy", 1500);
		Sleeper grumpy = new Sleeper("Grumpy", 1500);
		Joiner dopey = new Joiner("Dopey", sleepey);
		Joiner doc = new Joiner("Doc", grumpy);
		System.out.println("grumpy isInterrupted:" + grumpy.isInterrupted());
		grumpy.interrupt();
		System.out.println("grumpy isInterrupted:" + grumpy.isInterrupted());
	}
}


 
 

代码1-11运行结果:

grumpy isInterrupted:false
grumpy isInterrupted:true
Grumpy was interrupted. isInterrupted(): false
Doc join completed
Sleepy has awkened
Dopey join completed

在run()中,sleep()方法有可能在指定时间期满时返回,也可能被中断,catch字句中,将根据isInterrupted()的返回值报告这个中断,当另一个线程在线程上调用interrupt()时,将给该线程设定一个标志,表明该线程已经被中断。然而,异常被捕获时将清理这个标志,所以在catch字句中,在异常被捕获时这个标志总为假

Joiner线程将通过在Sleeper对象上调用join()方法等待Sleeper对象醒来,可在输出发现,不论Sleeper是中断或是正常结束,Joiner将和Sleeper一起结束


捕获异常

下面的任务会抛出一个异常,该异常会传播到其run()方法的外部

代码1-12

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExceptionThread implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		throw new RuntimeException();
	}

	public static void main(String[] args) {
		try {
			ExecutorService exec = Executors.newCachedThreadPool();
			exec.execute(new ExceptionThread());
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
			System.out.println("Exception has been handled");
		}
	}

}

代码1-12运行结果:

Exception in thread "pool-1-thread-1" java.lang.RuntimeException
at com.jerry.demo1.ExceptionThread.run(ExceptionThread.java:11)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)


可以看到Exception has been handled并没有打印在控制台

每个Thread对象上都附着一个异常处理器,java.lang.Thread.UncaughtExceptionHandler.uncaughtException(Thread, Throwable)会在线程因未捕获的异常而临近结束时被调用。为了使用它,可以创建一个新类型的ThreadFactory,每个Thread对象上附着一个Thread.UncaughtExceptionHandler

代码1-13

import java.util.concurrent.*;

class ExceptionThread2 implements Runnable {
	public void run() {
		Thread t = Thread.currentThread();
		System.out.println("run() by " + t);
		System.out.println("eh = " + t.getUncaughtExceptionHandler());
		throw new RuntimeException();
	}
}

class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
	public void uncaughtException(Thread t, Throwable e) {
		System.out.println("caught " + e);
	}
}

class HandlerThreadFactory implements ThreadFactory {
	public Thread newThread(Runnable r) {
		System.out.println(this + " creating new Thread");
		Thread t = new Thread(r);
		System.out.println("created " + t);
		t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
		System.out.println("eh = " + t.getUncaughtExceptionHandler());
		return t;
	}
}

public class CaptureUncaughtException1 {
	public static void main(String[] args) {
		ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());
		exec.execute(new ExceptionThread2());
	}
}

代码-13运行结果:

com.jerry.demo2.HandlerThreadFactory@90832e creating new Thread
created Thread[Thread-0,5,main]
eh = com.jerry.demo2.MyUncaughtExceptionHandler@1947496
run() by Thread[Thread-0,5,main]
eh = com.jerry.demo2.MyUncaughtExceptionHandler@1947496
com.jerry.demo2.HandlerThreadFactory@90832e creating new Thread
created Thread[Thread-1,5,main]
eh = com.jerry.demo2.MyUncaughtExceptionHandler@8a548b
caught java.lang.RuntimeException




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值