1.多线程常用方式
- 创建Thread
- 使用线程池
2.实现接口
- Runnable,无返回值
- Callable,可有返回值
3.异常捕获
线程运行过程中发生的异常,无法通过try catch方式,在外层进行捕获,例如
try {
new Thread(new Runnable() {
@Override
public void run() {
int i = 1 / 0;
}
}).start();
} catch (Exception e) {
System.out.println("error");
}
执行上面的代码,你会发现,error永远不会打印在你的控制台或是log中,原因为何,没去深究,不过我想大概是因为线程有自己独立的栈区
4.如何捕获异常
- 创建Thread方式 使用UncaughtExceptionHandler方式捕获运行时异常
try {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
int i = 1 / 0;
}
});
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("uncaughtException");
}
});
thread.start();
} catch (Exception e) {
System.out.println("error");
}
- 使用线程池方式 通常我们都会使用concurrent包中的一些工具类来创建使用线程池,Executors为我们提供了几种线程池,但是底层实现其实都是使用ThreadPoolExecutor,ThreadPoolExecutor预留了方法afterExecute可以让我们实现线程内异常的处理
private static ThreadPoolExecutor executorPool = new ThreadPoolExecutor(4, 20,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1),
new SimpleThreadFactory("executor"),
new CustomRejectedExecutionHandler()
) {
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t == null && r instanceof Future<?>) {
try {
Object result = ((Future<?>) r).get();
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt(); // ignore/reset
}
}
if (t != null) {
System.out.println("t is :" + t);
t.printStackTrace();
}
}
};
这样就可以在异常发生时,可以打印出异常信息,而不是被吃掉
5.被吃掉的原因
我们在sumbit任务到ThreadPool时,自动为我们包装成了FutureTask,而FutureTask对象在执行时,是会把异常吃掉,直到我们get FutureTask的执行结果时才会把异常抛出。相关的代码如下: