3.1 创建线程执行器

来源:互联网 发布:mac word文件丢失 编辑:程序博客网 时间:2024/04/30 12:27

创建线程执行器

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 2014pool-1-thread-2:任务开始时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-6:任务创建时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-1:任务创建时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-4:任务创建时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-8:任务创建时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-4:任务开始时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-3:任务创建时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-3:任务开始时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-7:任务创建时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-7:任务开始时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-8:任务开始时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-5:任务创建时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-5:任务开始时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-1:任务开始时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-10:任务创建时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-10:任务开始时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-6:任务开始时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-9:任务创建时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-9:任务开始时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-5:任务完成时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-6:任务完成时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-4:任务完成时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-10:任务完成时间:Mon Apr 21 16:06:28 CST 2014pool-1-thread-3:任务完成时间:Mon Apr 21 16:06:29 CST 2014pool-1-thread-9:任务完成时间:Mon Apr 21 16:06:29 CST 2014pool-1-thread-7:任务完成时间:Mon Apr 21 16:06:29 CST 2014pool-1-thread-2:任务完成时间:Mon Apr 21 16:06:29 CST 2014pool-1-thread-8:任务完成时间:Mon Apr 21 16:06:29 CST 2014pool-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:执行器线程数:1main:执行器线程数:2main:执行器线程数:3main:执行器线程数:3main:执行器线程数:3main:执行器线程数:3main:执行器线程数:3main:执行器线程数:3main:执行器线程数:3main:执行器线程数:3pool-1-thread-2:任务创建时间:Mon Apr 21 16:18:02 CST 2014pool-1-thread-2:任务开始时间:Mon Apr 21 16:18:02 CST 2014pool-1-thread-3:任务创建时间:Mon Apr 21 16:18:02 CST 2014pool-1-thread-3:任务开始时间:Mon Apr 21 16:18:02 CST 2014pool-1-thread-1:任务创建时间:Mon Apr 21 16:18:02 CST 2014pool-1-thread-1:任务开始时间:Mon Apr 21 16:18:02 CST 2014pool-1-thread-1:任务完成时间:Mon Apr 21 16:18:02 CST 2014pool-1-thread-1:任务创建时间:Mon Apr 21 16:18:02 CST 2014pool-1-thread-1:任务开始时间:Mon Apr 21 16:18:02 CST 2014pool-1-thread-2:任务完成时间:Mon Apr 21 16:18:03 CST 2014pool-1-thread-2:任务创建时间:Mon Apr 21 16:18:02 CST 2014pool-1-thread-2:任务开始时间:Mon Apr 21 16:18:03 CST 2014pool-1-thread-3:任务完成时间:Mon Apr 21 16:18:03 CST 2014pool-1-thread-3:任务创建时间:Mon Apr 21 16:18:02 CST 2014pool-1-thread-3:任务开始时间:Mon Apr 21 16:18:03 CST 2014pool-1-thread-1:任务完成时间:Mon Apr 21 16:18:03 CST 2014pool-1-thread-1:任务创建时间:Mon Apr 21 16:18:02 CST 2014pool-1-thread-1:任务开始时间:Mon Apr 21 16:18:03 CST 2014pool-1-thread-3:任务完成时间:Mon Apr 21 16:18:03 CST 2014pool-1-thread-3:任务创建时间:Mon Apr 21 16:18:02 CST 2014pool-1-thread-3:任务开始时间:Mon Apr 21 16:18:03 CST 2014pool-1-thread-2:任务完成时间:Mon Apr 21 16:18:03 CST 2014pool-1-thread-2:任务创建时间:Mon Apr 21 16:18:02 CST 2014pool-1-thread-2:任务开始时间:Mon Apr 21 16:18:03 CST 2014pool-1-thread-3:任务完成时间:Mon Apr 21 16:18:03 CST 2014pool-1-thread-3:任务创建时间:Mon Apr 21 16:18:02 CST 2014pool-1-thread-3:任务开始时间:Mon Apr 21 16:18:03 CST 2014pool-1-thread-2:任务完成时间:Mon Apr 21 16:18:04 CST 2014pool-1-thread-1:任务完成时间:Mon Apr 21 16:18:04 CST 2014pool-1-thread-3:任务完成时间:Mon Apr 21 16:18:04 CST 2014

可以看出,执行器运行的线程数没有超过3个。
0 0