3.1 创建线程执行器

创建线程执行器

Executor Framework概述

Java5引入了执行器框架(Executor Framework),这套框架分离了任务的创建和执行。使用执行器,仅需要实现Runnable接口的对象,然后将这些对象发送给执行器即可。执行器通过创建所需的线程,来负责这些Runnable对象的创建、实例化以及运行。而且,执行器使用了线程池来提高应用程序性能。当发送一个任务给执行器时,执行器会尝试使用线程池中的线程来执行这个任务,避免了不断地创建和销毁线程而导致系统吸能下降。


执行器的另一个重要优势是Callable接口。它类似于Runnable接口,但提供个两方面的增强:

  • Callable接口的主方法是call,可以返回结果。
  • 当发送一个Callable对象给执行器时,将获得一个实现了Future接口的对象。可以使用这个对象来控制Callable对象的状态和结果。

创建执行器

Executor Framework是由围绕着Executor和子接口ExecutorService的接口和类组成。主要使用的实现类是ThreadPoolExecutor类。ThreadPoolExecutor提供了4个重载的构造函数,这4个构造函数参数都比较复杂,所以一般都是通过工厂Executors的静态方法来创建。比如使用Executors的newCachedThreadPool方法创建一个缓存线程池的执行器,使用Executors.newFixedThreadPool方法创建固定大小的线程执行器。

创建缓存线程池执行器示例

下面用示例说明如何创建缓存线程池执行器:
public class CachedThreadPoolDemo {
    public static void main(String[] args){
        ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newCachedThreadPool();
        for(int i=0; i<10; i++){
            DummayTask task = new DummayTask();
            executor.execute(task);
        }

        executor.shutdown();
    }

}

class DummayTask implements Runnable{

    private Date initDate;

    DummayTask() {
        this.initDate = new Date();
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + ":任务创建时间:" + initDate);
        System.out.println(Thread.currentThread().getName() + ":任务开始时间:" + new Date());

        long delay = (long)(Math.random()*1000);
        try {
            Thread.sleep(delay);
            System.out.println(Thread.currentThread().getName() + ":任务完成时间:" + new Date());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

程序运行日志:


pool-1-thread-2:任务创建时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-2:任务开始时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-6:任务创建时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-1:任务创建时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-4:任务创建时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-8:任务创建时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-4:任务开始时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-3:任务创建时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-3:任务开始时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-7:任务创建时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-7:任务开始时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-8:任务开始时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-5:任务创建时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-5:任务开始时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-1:任务开始时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-10:任务创建时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-10:任务开始时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-6:任务开始时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-9:任务创建时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-9:任务开始时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-5:任务完成时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-6:任务完成时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-4:任务完成时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-10:任务完成时间:Mon Apr 21 16:06:28 CST 2014
pool-1-thread-3:任务完成时间:Mon Apr 21 16:06:29 CST 2014
pool-1-thread-9:任务完成时间:Mon Apr 21 16:06:29 CST 2014
pool-1-thread-7:任务完成时间:Mon Apr 21 16:06:29 CST 2014
pool-1-thread-2:任务完成时间:Mon Apr 21 16:06:29 CST 2014
pool-1-thread-8:任务完成时间:Mon Apr 21 16:06:29 CST 2014
pool-1-thread-1:任务完成时间:Mon Apr 21 16:06:29 CST 2014

创建固定大小的线程执行器示例

上例显示了缓存线程池执行器的使用方法,当需要执行新任务时,缓存线程池执行器就会创建新线程来执行,只有线程所运行的任务执行完成后并且这个线程可用,才会重用这些线程。这种机制情况下,如果发给过多任务将会使系统负荷过载。为避免这个问题,可以使用固定大小的线程执行器。这个执行器有一个线程最大值,如果发送超过这个最大值的任务,执行器将不再创建额外线程,剩下的任务将被阻塞直到执行器有空闲的线程可用。这样可以保证执行器不会是系统的负荷过载。下面示例演示了固定大小的线程执行器使用方法:
public class FixedThreadPoolDemo {
    public static void main(String[] args){
        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(3);
        for(int i=0; i<10; i++){
            DummayTask task = new DummayTask();
            executor.execute(task);
            System.out.println("main:执行器线程数:" + executor.getActiveCount());
        }
        executor.shutdown();
    }
}

程序运行日志:
main:执行器线程数:1
main:执行器线程数:2
main:执行器线程数:3
main:执行器线程数:3
main:执行器线程数:3
main:执行器线程数:3
main:执行器线程数:3
main:执行器线程数:3
main:执行器线程数:3
main:执行器线程数:3
pool-1-thread-2:任务创建时间:Mon Apr 21 16:18:02 CST 2014
pool-1-thread-2:任务开始时间:Mon Apr 21 16:18:02 CST 2014
pool-1-thread-3:任务创建时间:Mon Apr 21 16:18:02 CST 2014
pool-1-thread-3:任务开始时间:Mon Apr 21 16:18:02 CST 2014
pool-1-thread-1:任务创建时间:Mon Apr 21 16:18:02 CST 2014
pool-1-thread-1:任务开始时间:Mon Apr 21 16:18:02 CST 2014
pool-1-thread-1:任务完成时间:Mon Apr 21 16:18:02 CST 2014
pool-1-thread-1:任务创建时间:Mon Apr 21 16:18:02 CST 2014
pool-1-thread-1:任务开始时间:Mon Apr 21 16:18:02 CST 2014
pool-1-thread-2:任务完成时间:Mon Apr 21 16:18:03 CST 2014
pool-1-thread-2:任务创建时间:Mon Apr 21 16:18:02 CST 2014
pool-1-thread-2:任务开始时间:Mon Apr 21 16:18:03 CST 2014
pool-1-thread-3:任务完成时间:Mon Apr 21 16:18:03 CST 2014
pool-1-thread-3:任务创建时间:Mon Apr 21 16:18:02 CST 2014
pool-1-thread-3:任务开始时间:Mon Apr 21 16:18:03 CST 2014
pool-1-thread-1:任务完成时间:Mon Apr 21 16:18:03 CST 2014
pool-1-thread-1:任务创建时间:Mon Apr 21 16:18:02 CST 2014
pool-1-thread-1:任务开始时间:Mon Apr 21 16:18:03 CST 2014
pool-1-thread-3:任务完成时间:Mon Apr 21 16:18:03 CST 2014
pool-1-thread-3:任务创建时间:Mon Apr 21 16:18:02 CST 2014
pool-1-thread-3:任务开始时间:Mon Apr 21 16:18:03 CST 2014
pool-1-thread-2:任务完成时间:Mon Apr 21 16:18:03 CST 2014
pool-1-thread-2:任务创建时间:Mon Apr 21 16:18:02 CST 2014
pool-1-thread-2:任务开始时间:Mon Apr 21 16:18:03 CST 2014
pool-1-thread-3:任务完成时间:Mon Apr 21 16:18:03 CST 2014
pool-1-thread-3:任务创建时间:Mon Apr 21 16:18:02 CST 2014
pool-1-thread-3:任务开始时间:Mon Apr 21 16:18:03 CST 2014
pool-1-thread-2:任务完成时间:Mon Apr 21 16:18:04 CST 2014
pool-1-thread-1:任务完成时间:Mon Apr 21 16:18:04 CST 2014
pool-1-thread-3:任务完成时间:Mon Apr 21 16:18:04 CST 2014

可以看出,执行器运行的线程数没有超过3个。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值