Java中的线程池概述:
Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序 都可以使用线程池。
在开发过程中,合理地使用线程池能够带来3个好处:
- 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
- 提高响应速度。当任务到达时,就能立即执行,而不需要等待线程创建的过程。
- 提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源, 还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。但是,要做到合理利用 线程池,必须对其实现原理了如指掌。
线程池的实现原理
当向线程池提交一个任务之后,线程池是如何处理这个任务的呢?
从图中可以看出,当提交一个新任务到线程池时,线程池的处理流程如下。
1)线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作 线程来执行任务。如果核心线程池里的线程都在执行任务,则进入下个流程。
2)线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这 个工作队列里。如果工作队列满了,则进入下个流程。
3)线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程 来执行任务。如果已经满了,则交给饱和策略来处理这个任务。
ThreadPoolExecutor执行execute()方法的示意图,如图所示:
线程池的使用
我们可以通过new ThreadPoolExecutor
来创建一个线程池:
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, milliseconds,runnableTaskQueue, handler);
向线程池提交任务:
可以使用两个方法向线程池提交任务,分别为execute()
和 submit()
方法。
execute()
方法 用于提交不需要返回值的任务,即:Runnable任务,所以无法判断任务是否被线程池执行成功。
threadsPool.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
}
});
submit()
方法用于提交需要返回值的任务,即Callbale任务。
// 1 提交任务
Future<Object> future = executor.submit(harReturnValuetask);
//2 获取任务的执行结果
try {
Object s = future.get();
} catch (InterruptedException e) {
// 处理中断异常
} catch (ExecutionException e) {
// 处理无法执行任务异常
} finally {
// 关闭线程池
executor.shutdown();
}
线程池会返回一个 Future
类型的对象,通过这个 Future对象 可以判断任务是否执行成功,并且可以通过future的 get()
方法来获取返回值。
注:get()方法会阻塞当前线程直到 当前线程所提交的所有任务都完成,而使用get(long timeout,TimeUnit unit)
方法则会阻塞当前线 程一段时间后立即返回,这时候有可能任务没有执行完。