ExecutorService创建线程池的四种方法

newCachedThreadPool

缓存型线程池,先查看池中有没有以前建立的线程,如果有,就重用,如果没有,就建一个新的线程加入池中。如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
使用方法为:
ExecutorService executorService = Executors.newCachedThreadPool();
源码为:

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0,//线程池维护线程的最少数量
                     Integer.MAX_VALUE,//线程池维护线程的最大数量
                     60L,//线程池维护线程所允许的空闲时间,60秒
                    TimeUnit.SECONDS,//线程池维护线程所允许的空闲时间的单位
                    new SynchronousQueue<Runnable>());
    }

使用例子:

public static void main(String[] args){
        ExecutorService exe= Executors.newCachedThreadPool();
        for(int i=1;i<6;i++){
            final int taskID=i;
            exe.execute(new Runnable() {
                public void run() {
                    for(int j=1;j<4;j++){
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("线程ID:"+taskID+",执行第 "+j+" 次");
                    }
                }
            });
        }
    }

执行结果:

线程ID:3,执行第 1 次
线程ID:4,执行第 1 次
线程ID:2,执行第 1 次
线程ID:5,执行第 1 次
线程ID:1,执行第 1 次

线程ID:2,执行第 2 次
线程ID:3,执行第 2 次
线程ID:4,执行第 2 次
线程ID:1,执行第 2 次
线程ID:5,执行第 2 次

线程ID:2,执行第 3 次
线程ID:3,执行第 3 次
线程ID:4,执行第 3 次
线程ID:5,执行第 3 次
线程ID:1,执行第 3 次

可以看到执行结果是5个任务在交替进行的

newCachedThreadPool的总结:

1.重用:缓存型池子,先查看池中有没有以前建立的线程,如果有,就reuse;如果没有,就建一个新的线程加入池中
2.使用场景:缓存型池子通常用于执行一些生存期很短的异步型任务,因此在一些面向连接的daemon型SERVER中用得不多。
3.超时:能reuse的线程,必须是timeout IDLE内的池中线程,缺省timeout是60s,超过这个IDLE时长,线程实例将被终止及移出池。
4.结束:注意,放入CachedThreadPool的线程不必担心其结束,超过TIMEOUT不活动,其会自动被终止。

newFixedThreadPool

定长线程池,可控制线程最大并发数。如果当前需要执行的任务超过池大小,那么多出的任务处于等待状态,直到有空闲下来的线程执行任务,如果当前需要执行的任务小于池大小,空闲的线程也不会去销毁。
使用方法为:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
源码为:

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(
                            nThreads,//线程池维护线程的最少数量
                            nThreads,//线程池维护线程的最大数量
                            0L, //线程池维护线程所允许的空闲时间
                            TimeUnit.MILLISECONDS,//线程池维护线程所允许的空闲时间的单位
                   new LinkedBlockingQueue<Runnable>());
    }

使用例子:

public static void main(String[] args){
        ExecutorService exe= Executors.newFixedThreadPool(3);
        for(int i=1;i<6;i++){
            final int taskID=i;
            exe.execute(new Runnable() {
                public void run() {
                    for(int j=1;j<4;j++){
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("线程ID:"+taskID+",执行第 "+j+" 次");
                    }
                }
            });
        }

    }

执行结果:

线程ID:2,执行第 1 次
线程ID:1,执行第 1 次
线程ID:3,执行第 1 次

线程ID:2,执行第 2 次
线程ID:3,执行第 2 次
线程ID:1,执行第 2 次

线程ID:2,执行第 3 次
线程ID:3,执行第 3 次
线程ID:1,执行第 3 次

线程ID:4,执行第 1 次
线程ID:5,执行第 1 次
线程ID:4,执行第 2 次

线程ID:5,执行第 2 次
线程ID:4,执行第 3 次
线程ID:5,执行第 3 次

创建了一个固定大小的线程池,容量为3,然后循环执行了5个任务。由输出结果可以看到,前3个任务首先执行完,然后空闲下来的线程去执行第4,5个任务。
newFixedThreadPool的总结:

1.重用:fixedThreadPool与cacheThreadPool差不多,也是能reuse就用,但不能随时建新的线程
2.固定数目:其独特之处在于,任意时间点,最多只能有固定数目的活动线程存在,此时如果有新的线程要建立,只能放在另外的队列中等待,直到当前的线程中某个线程终止直接被移出池子
3.超时:和cacheThreadPool不同,FixedThreadPool没有IDLE机制(可能也有,但既然文档没提,肯定非常长,类似依赖上层的TCP或UDP IDLE机制之类的),
4,使用场景:所以FixedThreadPool多数针对一些很稳定很固定的正规并发线程,多用于服务器

newScheduledThreadPool

调度型线程池,支持定时及周期性任务执行,也是一个固定长度的线程池。
使用方法为:
ScheduledExecutorService exe= Executors.newScheduledThreadPool(3);
源码为:

public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, // 线程池维护线程的最少数量
        Integer.MAX_VALUE, //线程池维护线程的最大数量
        0, // 线程池维护线程所允许的空闲时间
        NANOSECONDS,//线程池维护线程所允许的空闲时间的单位
        new DelayedWorkQueue());
    }

使用例子:

  public static void main(String[] args){
        ScheduledExecutorService exe= Executors.newScheduledThreadPool(3);
            for(int i=1;i<6;i++){
                final int taskID=i;
                exe.scheduleAtFixedRate(new Runnable() {
                    public void run() {
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("线程:"+taskID+",时间:"+ LocalDateTime.now()+" 执行一次");
                    }
                }, 0, 2, TimeUnit.SECONDS);
            }
    }

代码scheduleAtFixedRate后面的参数 0 表示立即执行,2表示2秒执行一次调度。执行结果:

线程:1,时间:2016-12-11T13:09:18.544 执行一次
线程:2,时间:2016-12-11T13:09:18.544 执行一次
线程:3,时间:2016-12-11T13:09:18.544 执行一次

线程:5,时间:2016-12-11T13:09:20.557 执行一次
线程:1,时间:2016-12-11T13:09:20.557 执行一次
线程:4,时间:2016-12-11T13:09:20.557 执行一次

线程:4,时间:2016-12-11T13:09:22.572 执行一次
线程:2,时间:2016-12-11T13:09:22.572 执行一次
线程:3,时间:2016-12-11T13:09:22.572 执行一次

线程:5,时间:2016-12-11T13:09:24.586 执行一次
线程:1,时间:2016-12-11T13:09:24.586 执行一次
线程:2,时间:2016-12-11T13:09:24.586 执行一次

newScheduledThreadPool的线程池大小只设置了3,所以一次只能执行3个线程,然后可以看到每2秒执行一次任务调度。

newSingleThreadExecutor

单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果当前线程意外终止,会创建一个新线程继续执行任务,这和我们直接创建线程不同,也和newFixedThreadPool(1)不同。
使用方法为:
ExecutorService exe= Executors.newSingleThreadExecutor();
源码为:

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

使用例子:

public static void main(String[] args){
        ExecutorService exe= Executors.newSingleThreadExecutor();
        for(int i=1;i<6;i++){
            final int taskID=i;
            exe.execute(new Runnable() {
                public void run() {
                    for(int j=1;j<4;j++){
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("线程ID:"+taskID+",执行第 "+j+" 次");
                    }
                }
            });
        }
    }

执行结果:

线程ID:1,执行第 1 次
线程ID:1,执行第 2 次
线程ID:1,执行第 3 次
线程ID:2,执行第 1 次
线程ID:2,执行第 2 次
线程ID:2,执行第 3 次
线程ID:3,执行第 1 次
线程ID:3,执行第 2 次
线程ID:3,执行第 3 次
线程ID:4,执行第 1 次
线程ID:4,执行第 2 次
线程ID:4,执行第 3 次
线程ID:5,执行第 1 次
线程ID:5,执行第 2 次
线程ID:5,执行第 3 次

每个结果都是相隔0.5秒打印出来的,顺序执行下去。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值