线程池:
简单理解,就是一个管理线程的池子。
- 它帮我们管理线程,避免增加创建线程和销毁线程的资源消耗。因为线程其实也是一个对象,创建一个对象,需要经过类加载过程,销毁一个对象,需要走GC垃圾回收流程,都是需要资源开销的。
- 提高响应速度。如果任务达到了,相对于从线程池拿线程,重新去创建一条线程执行,速度要慢很多。
- 重复利用。线程使用完,再放回线程池,可以达到重复利用的效果,节省资源。
线程池的创建:
线程池可以通过ThreadpoolExecutor来创建:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
几个核心参数的作用:
- corePoolSize:线程池核心线程数最大值
- maximumPoolSize: 线程池最大线程数大小
- keepAliveTime: 线程中非核心线程空闲的存活时间大小
- unit: 线程空闲存活时间单位
- workQueue:存放任务的阻塞队列
- threadFactory:用于设置创建线程的工厂,可以给创建的线程设置有意义的名字,方便排查问题。
- handler:线程池的饱和策略事件,主要有四种类型。
任务执行:
- 提交一个任务,线程池里存活的核心线程数小于线程数corePoolSize时,线程池会创建一个核心线程去处理提交的任务。
- 如果线程核心线程数已满,线程数已经等于corePoolSize,一个新提交的任务,会被放进任务队列workQueue排队等待执行。
- 当线程池里面已经存活的线程数已经等于corePoolSize,并且任务队列workQueue也满,判断线程数是否已满,如果没有,创建一个非核心线程执行提交的任务。、
- 如果当前的线程数达到了maximumPoolSize,还有新的任务过来的话,直接采用拒绝策略处理。
四种拒绝策略:
- AbortPolicy(抛出一个异常,默认的)
- DiscardPolicy(直接丢弃任务)
- DiscaOldestPolicy(丢弃队列里最老的任务,将当前这个任务继续提交给线程池)
- callerRunsPolicy(交给线程池调用所在的线程进行处理)
线程池异常处理:
在使用线程池处理任务的时候,任务代码可能抛出RuntimeException,抛出异常后,线程池可能捕获它,也可能创建一个新的线程来代替异常的线程,我们可能无法感知任务出现了异常,因此我们需要考虑线程池异常情况。
ExecutorService executorService=Executors.newFixedThreadPool(6); for (int i = 0; i < 6; i++) { executorService.submit(()->{ System.out.println("current thread name"+Thread.currentThread().getName()); try { Object object=null; System.out.println("result"+object.toString()); }catch (Exception e){ System.out.println("program occur"+e); } }); }
看下源码:
/** * @throws RejectedExecutionException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public Future<?> submit(Runnable task) { if (task == null) throw new NullPointerException(); RunnableFuture<Void> ftask = newTaskFor(task, null); execute(ftask); return ftask; } protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { return new FutureTask<T>(runnable, value); } public FutureTask(Runnable runnable, V result) { this.callable = Executors.callable(runnable, result); this.state = NEW; // ensure visibility of callable } public static <T> Callable<T> callable(Runnable task, T result) { if (task == null) throw new NullPointerException(); return new RunnableAdapter<T>(task, result); }
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get(); if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); } else if (!addWorker(command, false)) reject(command); }
public void run() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try { result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran) set(result); } } finally { // runner must be non-null until state is settled to // prevent concurrent calls to run() runner = null; // state must be re-read after nulling runner to prevent // leaked interrupts int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } }
通过以上分析,submit执行的任务,可以通过Future对象的get()方法接收抛出的异常,再进行处理。因此可以通过future.get()来对异常进行处理。
public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(6); for (int i = 0; i < 6; i++) { Future future = executorService.submit(() -> { System.out.println("current thread name" + Thread.currentThread().getName()); Object object = null; System.out.println("result" + object.toString()); }); try { future.get(); } catch (Exception e) { System.out.println("program occur" + e); } } }
因此可以处理异常:
1. 在任务代码try/catch进行异常捕获。
2. 通过Future对象的get方法抛出异常,再进行捕获。
3. 为工作者线程设置UncaughtExceptionHandler,在方法中处理异常。
public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(6, t -> { Thread thread = new Thread(t); thread.setUncaughtExceptionHandler((thread1, e) -> { System.out.println(thread1.getName() + " occur:" + e); }); return thread; }); for (int i = 0; i < 8; i++) { executorService.execute(() -> { Object object = null; System.out.println("result" + object.toString()); }); } }