关于线程的基础知识,比如线程的创建(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<=ucpu<=1 w/c:是等待时间和计算时间的比值
一般需要根据任务的类型来配置线程池大小:
如果是cpu密集型任务,就需要尽量压榨cpu,参考值可以设为 ncpu+1
如果是io密集型任务,参考值可以设置为2*ncpu
当然,这只是一个参考值,具体的设置还需要根据实际情况进行调整,比如可以先将线程池大小设置为参考值,再观察任务运行情况和系统负载、资源利用率来进行适当调整。
有的时候我们的应用需要拿到线程执行完毕后的返回值,这个时候就需要用到callable和future以及futuretask了。下面是一个实例,copy就可以运行,也可以看实例有详细注释说明。