Java --- Executor
Executor
Executor: 一个可以执行提交的任务的对象!JDK java.util.concurrent包中关于Executor的主要类和接口的类图如下:
任务对于Java来说就是实现了runnable或 Callable接口的类,有了Executor,那我们执行任务就有了3种选择:
1. 用任务创建一个Thread对象,调用其start()方法。
2. 将任务交给一个Executor来执行
3. 在当前线程中执行任务。
相比于简单的创建Thread执行,Executor 提供除执行任务之外的功能,也是我们使用Executor的原因:
1. 执行器状态和管理:isTerminated(),isShutdown(),shutdown(),shutdownNow()
2. 获取任务对应的Future
3. 主要实现ThreadPoolExecutor提供了线程池,执行器统计,提交拒绝处理器等功能。
ThreadPoolExecutor
ThreadPoolExecutor实现提供了ExecutorService接口实现以及一些有用的方法。
任务的提交:
ThreadPoolExecutor中使用BlockingQueue<Runnable>来保存提交的任务。ExecutorService的提交任务方法最终会调用execute(runnable) 方法。
publicvoid execute(Runnable command) { if (command == null) thrownew NullPointerException(); //根据需要是否添加worker intc = ctl.get(); if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } if (isRunning(c) && workQueue.offer(command)) { //重复检查 intrecheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); elseif (workerCountOf(recheck) == 0) addWorker(null, false); } elseif (!addWorker(command, false)) reject(command); } |
BlockingQueue<Runnable>根据线程池的不同也有所不同:
CachedThreadPool | SynchronousQueue<Runnable> |
FixedSizedThreadpool | LinkedBlockingQueue<Runnable> |
SingleThreadExecutor | LinkedBlockingQueue<Runnable> |
ScheduledThreadPoolExecutor | DelayedWorkQueue() |
从任务提交的代码中可以看出,在任务提交时会根据配置来决定是否增加新的worker,而Queue的选择不同也根据不同特点的线程池而不同。
线程池
ThreadPoolExecutor内部实现了一个继承自AQS,实现Runnalbe接口的worker类,并使用HashSet<Worker>来保存所有的工作者。
Worker.run()
finalvoid runWorker(Worker w) { Thread wt = Thread.currentThread(); Runnable task = w.firstTask; w.firstTask = null; w.unlock(); // allow interrupts booleancompletedAbruptly = true; try { while (task != null || (task = getTask()) != null) { w.lock(); // If pool is stopping, ensure thread is interrupted; // if not, ensure thread is not interrupted. This // requires a recheck in second case to deal with // shutdownNow race while clearing interrupt if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()) wt.interrupt(); try { beforeExecute(wt, task); Throwable thrown = null; try { task.run(); } catch (RuntimeException x) { thrown = x; throwx; } catch (Error x) { thrown = x; throwx; } catch (Throwable x) { thrown = x; thrownew Error(x); } finally { afterExecute(task, thrown); } } finally { task = null; w.completedTasks++; w.unlock(); } } completedAbruptly = false; } finally { processWorkerExit(w, completedAbruptly); } }
|
再来看下BlockingQueue为什么会有所不同:
CachedThreadPool: 线程池中的最大数量为Integer.MAX_VALUE,也就是说每一次添加一个任务都会有一个要么是空闲的工作者要么是新加的工作者来执行这个任务,也就是说已提交任务就会短时间内有一个工作者来接收,因此使用SynchronousQueue。而该线程池中的的工作线程默认空闲时间超过6秒就会关闭释放,因此CachedThreadPool的主要应用场景是大量运行时间短的异步计算任务。
FixSizedThreadPoolExecutor,SingleThreadPoolExecutor:这些线程池的工作者是有最大值限制的,因此当任务较多的时候是需要一个队列来缓存等待执行的任务,因此使用了LinkedBlockingQueue这个线程安全的队列。
ScheduledThreadPoolExecutor: 这个线程池实现了ScheduledExecutorService的定时执行功能,因此使用了DelayWorkQueue,这个队列实现了根据定时任务的时间顺序到期返回带执行任务的功能。
RejectedExecutionHandler拒绝异常处理器
ThreadPoolExecutor可以定制在由于任务队列满或其它原因的情况下的处理策略,我们可以实现自己的处理策略,ThreadPoolExecutor提供了4种实现可以直接使用:
CallerRunsPolicy:提交失败后,则提交线程运行。
AbortPolicy: 提交失败返回异常。
DiscardPolicy: 忽略错误
DiscardOldestPolicy: 移除最久的任务。
下面是DiscardOldestPolicy代码:
publicvoid rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } |
另外还有getCompletedTaskCount(),getTaskCount()等方法可以返回执行器的状态和统计信息。
Java.util.concurrent.Executors
该类提供了获取ExecutorSerivce实例和一些Executor相关的静态帮助方法。比如我们可以向下面一样方便的使用线程池。
ExecutorService executor = Executors.newSingleThreadExecutor(); executor.execute(new UserInfoCacheRunnable()); |