天天看点

Java并发编程详解线程的基础知识线程池Callable和Future以及FutureTask的实例应用

关于线程的基础知识,比如线程的创建(thread,runnable),进程和线程的区别,以及线程的sleep、synchronized、wait、interrupt、join、yield等方法就不详细讲解了。有需要的可以参考海子大神的文章。

创建线程池

在java doc中,并不提倡我们直接使用threadpoolexecutor,而是使用executors类中提供的几个静态方法来创建线程池:

<a></a>

线程池的使用

在工作中如何设置线程池的大小呢?

设置线程池的大小

线程池的理想大小取决于被提交任务的类型以及所部署系统的特性。在代码中通常不会固定线程池的大小,而应该通过某种配置机制来提供,或者根据runtime.availableprocessors来动态计算。

幸运的是,要设置线程池的大小也并不困难,只需要避免“过大”和“过小”这两种极端情况。如果线程池过大,那么大量的线程将在相对很少的cpu和内存资源上发生竞争,这不仅会导致更高的内存使用量,而且还可能耗尽资源。如果线程池过小,那么将导致许多空间的处理器无法执行工作,从而降低吞吐率。

要想正确地设置线程池的大小,必须分析计算环境、资源预算和任务的特性。在部署的系统中有多少个cpu?多大的内存?任务是计算密集型、i/o密集型还是二者皆可?它们是否需要像jdbc连接这样的稀缺资源?如果需要执行不同类别的任务,并且它们之间的行为相差很大,那么应该考虑使用多个线程池,从而使每个线程池可以根据各自的工作负载来调整。

对于计算密集型的任务,在拥有ncpu个处理器的系统上,当线程池的大小为 ncpu+1 时,通常能实现最优的利用率。

线程池的最优大小等于:

给定下列定义:

ncpu是cpu的数目,一般可以通过这个公式获取 int n_cpus = runtime.getruntime().availableprocessors() ucpu:cpu的利用率,范围为 0&lt;=ucpu&lt;=1 w/c:是等待时间和计算时间的比值

一般需要根据任务的类型来配置线程池大小:

  如果是cpu密集型任务,就需要尽量压榨cpu,参考值可以设为 ncpu+1

  如果是io密集型任务,参考值可以设置为2*ncpu

  当然,这只是一个参考值,具体的设置还需要根据实际情况进行调整,比如可以先将线程池大小设置为参考值,再观察任务运行情况和系统负载、资源利用率来进行适当调整。

  

    有的时候我们的应用需要拿到线程执行完毕后的返回值,这个时候就需要用到callable和future以及futuretask了。下面是一个实例,copy就可以运行,也可以看实例有详细注释说明。