ThreadPoolExecutor
提问?
1,为什么不能使用JDK自带的Executors去创建线程池。 (阿里手册中也有这个限制)?
比如:ExecutorService executorService = Executors.newCachedThreadPool();
查看源码:
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
Integer.MAX_VALUE:这个会造成非常大的问题,很容易OOM。
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
Integer.MAX_VALUE:这个会造成非常大的问题,很容易OOM。
ExecutorService executorService2 = Executors.newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
LinkedBlockingQueue(),默认也是Integer.MAX_VALUE长度,对列容易堆积到很大
的时候就会造成OOM。
ExecutorService executorService1 = Executors.newFixedThreadPool(1);
源码查看:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
LinkedBlockingQueue(),默认也是Integer.MAX_VALUE长度,对列容易堆积到很大
的时候就会造成OOM。
如果一个线程池的线程异常了,如何处理这个异常?
1,必须要求不能影响其他线程工作。
public class ThreadPoolExecutorExceptionProcess {
public static void main(String[] args) {
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("DeviceStatusThreadPoolExecutor Thread").build();
int queueCapacity = 2, corePoolSize = 2, maximumPoolSize = 2;
ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(queueCapacity);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 10,
TimeUnit.SECONDS, arrayBlockingQueue);
threadPoolExecutor.execute(new MyThread(2));
threadPoolExecutor.submit(new MyThread(2));
}
static class MyThread extends Thread {
private int i;
public MyThread(int i) {
this.i = i;
}
@Override
public void run() {
System.out.println(i+"执行了。。。。。。");
throw new RuntimeException("run exception");
}
}
}
这个代码你们心里清楚如何处理吗?
threadPoolExecutor.execute(new MyThread(2));
threadPoolExecutor.submit(new MyThread(2));
那个会抛出异常? execute还是submit。
执行execute方法
执行submit方法
异常吃了。
我们看看这个两个方法的源码
public void execute(Runnable command)
public Future<?> submit(Runnable task)
Submit方法有一个 Future对象
执行execute断点debug
我们看到执行到了 afterExexute(task,thrown);这个方法。这个方法可以扩展你需要捕获的异常处理,继续debug
这个时候会调用uncaughtException这个方法
这个是一个接口的方法,ThreadGroup实现了其接口,继续debug
可以看到来了到这里。最终打印出来异常栈数据和信息。 UncaughtExceptionHandler解释一下这个接口。
就是一个线程因未捕获异常而即将终止的时候,JVM蒋使用Thread.getUncaughtExceptionHandler()获取已经设置的UncaughtExceptionHandler实例并且通过调用uncaughtException方法而传递相关的异常信息,如果一个线程没有明确的制定UncaughtExceptionHandler,就会让ThreadGroup对象作为他的handler,如果ThreadGroup对象的异常没有特殊要求,ThreadGroup就调用转发给默认的异常处理器就是上面截图看到的处理。
单个线程处理异常的方式
//单线程线程异常处理方式
Thread thread=new Thread();
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
//处理异常
}
});
异常处理的常见方式
1,直接在我们的业务方法中直接try-catch捕获所有的异常,直接在catch块中进行异常处理。
2,线程池方式处理 继承ThreadPoolExecutor实现afterExecute方法的实现就可以了
public class ThreadPoolExecutorExtend extends ThreadPoolExecutor {
public ThreadPoolExecutorExtend(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
//错误自定义处理
System.out.println("自定义错误处理");
}
}
2,设置UncaughtExceptionHandler
public class ThreadPoolExecutorExceptionProcess {
public static void main(String[] args) {
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("DeviceStatusThreadPoolExecutor Thread").build();
int queueCapacity = 2, corePoolSize = 2, maximumPoolSize = 2;
ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(queueCapacity);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutorExtend(corePoolSize, maximumPoolSize, 10,
TimeUnit.SECONDS, arrayBlockingQueue, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
//自定义错误
}
});
return thread;
}
});
//单独实例线程异常处理方式
MyThread thread=new MyThread(2);
threadPoolExecutor.execute(thread);
}
static class MyThread extends Thread {
private int i;
public MyThread(int i) {
this.i = i;
// this.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
// @Override
// public void uncaughtException(Thread t, Throwable e) {
// System.out.println("是我自己处理的异常"+t.getName()+e.getMessage());
// }
// });
}
@Override
public void run() {
System.out.println(i+"执行了。。。。。。");
throw new RuntimeException("run exception");
}
}
}
3,自定义ThreadGroup进行错误处理
public class ThreadPoolExecutorExceptionProcess {
static class ThreadGroupExtend extends ThreadGroup{
public ThreadGroupExtend(String name) {
super(name);
}
public ThreadGroupExtend(ThreadGroup parent, String name) {
super(parent, name);
}
@Override
public void uncaughtException(Thread t, Throwable e) {
//异常业务处理
System.out.println("业务异常处理。。。。");
}
}
public static void main(String[] args) {
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("DeviceStatusThreadPoolExecutor Thread").build();
int queueCapacity = 2, corePoolSize = 2, maximumPoolSize = 2;
ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(queueCapacity);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutorExtend(corePoolSize, maximumPoolSize, 10,
TimeUnit.SECONDS, arrayBlockingQueue, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(new ThreadGroupExtend("CustomerThreadGroup"),r);
}
});
//单独实例线程异常处理方式
MyThread thread=new MyThread(2);
threadPoolExecutor.execute(thread);
}
static class MyThread extends Thread {
private int i;
public MyThread(int i) {
this.i = i;
// this.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
// @Override
// public void uncaughtException(Thread t, Throwable e) {
// System.out.println("是我自己处理的异常"+t.getName()+e.getMessage());
// }
// });
}
@Override
public void run() {
System.out.println(i+"执行了。。。。。。");
throw new RuntimeException("run exception");
}
}
}
submit方法错误处理方式
Future<?> submit = threadPoolExecutor.submit(thread);
try {
submit.get();
} catch (Exception e) {
//错误处理
}
源码分析
执行submit方法—> 同样会调用threadPoolExecutor的execute(ftask)
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
继续调用threadPoolExecutor的 runWorker(Worker w)
可以看到已经被封装成了FutureTask了,我们进入到FutureTask中去看看run方法 debug
看看异常,紧接着我们进入到setException里面去看看
异常数据被赋值到这对象上。
然后在调用 get方法
在调用 report方法
这个时候x就被赋值为异常对象数据。返回
总结
1,java线程池会捕获任务抛出的异常和错误,处理策略会受到我们提交任务的方式而不同。
2,submit()方式提交的任务会返给我们一个Future,如果业务方法有抛出异常,当我们调用java.util.concurrent.Future#get()方法时会抛出包装后的java.util.concurrent.ExecutionException。自己处理相应的错误
3,execute()方式提交的任务,java处理的默认策略是使用System.err.print("Exception in thread “” + t.getName() + “” ")输出日志,但是该日志不会打印到我们的日志文件中,只会在catalina.out文件中。
4,可以修改java线程池的默认处理策略,具体修改方式见上面如何处理线程异常。