简介
newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程,在需要时使用提供的 ThreadFactory 创建新线程。
newCachedThreadPool()创建的线程池的特性是:自动回收不使用的线程(终止并从缓存中移除那些已有 60 秒钟未被使用的线程),(在无可用线程的情况下)自动的为新来的task创建新线程。
正是因为这种特性,在小任务量,任务时间执行短的场景下能提高性能。然后如果在大量任务,且任务执行之间较长的场景中,系统将会超负荷。性能极低。
newFixedThreadPool(int nThreads) 就是来解决以上问题的。它创建一个固定大小的线程池,如果task任务数量大于nThreads数量,那么这些任务将在队列中排队,直到有可用线程再执行。
讲了2章了,可能有得人还不知道为什么要强转成ThreadPoolExecutor,可以看下面的源码,和下面的类图就明白了
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newSingleThreadExecutor:
只创建一个线程的线程池。多余的task将以无界队列来运行。也就是阻塞到有可用线程才能运行。
示例
创建固定大小的线程池
场景描述:下面示例讲的是:创建一个固定大小的线程执行器线程池,然后循环创建几个task任务执行。观察线程数量和名称。
/**
* Created by zhuqiang on 2015/8/25 0025.
*/
public class Client {
public static void main(String[] args) {
ThreadPoolExecutor es = (ThreadPoolExecutor) Executors.newFixedThreadPool(3);
// es.shutdown(); // 如果先关闭再执行任务,则会拒绝执行任务,抛出RejectedExecutionException异常
for (int i = 0; i < 10 ; i++) {
es.execute(new Task(es,"task-"+i));
}
es.shutdown();
}
}
class Task implements Runnable{
private ThreadPoolExecutor es;
private String name;
public Task(ThreadPoolExecutor es, String name) {
this.es = es;
this.name = name;
}
@Override
public void run() {
try {
long timeout = (long) (Math.random() * 10);
TimeUnit.SECONDS.sleep(timeout);
System.out.println(Thread.currentThread().getName() + "...执行完成..task=" + name +" 耗时:" + timeout);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
某一次的运行结果:
pool-1-thread-2...执行完成..task=task-1 耗时:0
pool-1-thread-1...执行完成..task=task-0 耗时:3
pool-1-thread-3...执行完成..task=task-2 耗时:4
pool-1-thread-2...执行完成..task=task-3 耗时:5
pool-1-thread-1...执行完成..task=task-4 耗时:5
pool-1-thread-3...执行完成..task=task-5 耗时:7
pool-1-thread-3...执行完成..task=task-8 耗时:0
pool-1-thread-2...执行完成..task=task-6 耗时:8
pool-1-thread-1...执行完成..task=task-7 耗时:7
pool-1-thread-3...执行完成..task=task-9 耗时:8
结果说明:可以看到,创建了3个数量的线程池,在执行中,也只会使用这三个线程数量,而其他的则会阻塞等待执行。
创建固定大小的线程池的时候使用ThreadFactory
ThreadFactory的作用:构造一个新 Thread。实现也可能初始化属性、名称、守护程序状态、ThreadGroup 等等。
在写demo的时候,我认为最麻烦的就是,设置循环中创建的线程的join方法。 在没有使用线程池的时候,在循环中调用这个方法都麻烦,要么抛出异常,要么就只有再循环一次来单独设置。 就这个场景而言,使用ThreadFactory来就很简单了。 ——————– 好把,我以为在工厂中,自己调用join方法能行。但是测试过了。视乎没有效果。 那就只能看下用法。场景用途我暂时也不知道了
示例如下:
/**
* Created by zhuqiang on 2015/8/25 0025.
*/
public class Client {
public static void main(String[] args) {
// ThreadPoolExecutor es = (ThreadPoolExecutor) Executors.newFixedThreadPool(3); //1 该注释代码。和下面为使用工厂的对比。
ThreadPoolExecutor es = (ThreadPoolExecutor) Executors.newFixedThreadPool(3, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("xxxx" + thread.getId()); //对新创建的线程做一些操作
return thread;
}
});
for (int i = 0; i < 10 ; i++) {
es.execute(new Task(es,"task-"+i));
}
es.shutdown();
}
}
class Task implements Runnable{
private ThreadPoolExecutor es;
private String name;
public Task(ThreadPoolExecutor es, String name) {
this.es = es;
this.name = name;
}
@Override
public void run() {
try {
long timeout = (long) (Math.random() * 10);
TimeUnit.SECONDS.sleep(timeout);
System.out.println(Thread.currentThread().getName() + "...执行完成..task=" + name +" 耗时:" + timeout);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
某一次的执行结果:
xxxx12...执行完成..task=task-0 耗时:3
xxxx12...执行完成..task=task-3 耗时:2
xxxx14...执行完成..task=task-2 耗时:6
xxxx13...执行完成..task=task-1 耗时:7
xxxx13...执行完成..task=task-6 耗时:0
xxxx12...执行完成..task=task-4 耗时:4
xxxx13...执行完成..task=task-7 耗时:6
xxxx14...执行完成..task=task-5 耗时:7
xxxx12...执行完成..task=task-8 耗时:5
xxxx13...执行完成..task=task-9 耗时:8