[笔记][Java7并发编程实战手册]4.3 创建固定的线程执行器newFixedThreadPool线程池

来源:互联网 发布:川崎机器人编程手册 编辑:程序博客网 时间:2024/05/15 04:49

[笔记][Java7并发编程实战手册]系列目录


简介

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    耗时:0pool-1-thread-1...执行完成..task=task-0    耗时:3pool-1-thread-3...执行完成..task=task-2    耗时:4pool-1-thread-2...执行完成..task=task-3    耗时:5pool-1-thread-1...执行完成..task=task-4    耗时:5pool-1-thread-3...执行完成..task=task-5    耗时:7pool-1-thread-3...执行完成..task=task-8    耗时:0pool-1-thread-2...执行完成..task=task-6    耗时:8pool-1-thread-1...执行完成..task=task-7    耗时:7pool-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    耗时:3xxxx12...执行完成..task=task-3    耗时:2xxxx14...执行完成..task=task-2    耗时:6xxxx13...执行完成..task=task-1    耗时:7xxxx13...执行完成..task=task-6    耗时:0xxxx12...执行完成..task=task-4    耗时:4xxxx13...执行完成..task=task-7    耗时:6xxxx14...执行完成..task=task-5    耗时:7xxxx12...执行完成..task=task-8    耗时:5xxxx13...执行完成..task=task-9    耗时:8
0 0
原创粉丝点击