ExecutorService

接口 java.util.concurrent.ExecutorService 表述了异步执行的机制,并且可以让任务在后台执行。在下面的例子中可以发现线程被循环创建,但是启动线程却不是连续的,而是由ExecutorService决定的。
ExecutorService是一个接口,继承了Executor。而Executor亦是一个接口,该接口只包含了一个方法:void execute(Runnable command);,该方法接收一个 Runable 实例,它用来执行一个任务,任务即一个实现了 Runnable 接口的类。

创建ExecutorService:
Executors 提供了一系列工厂方法用于创先线程池,返回的线程池都实现了 ExecutorService 接口。

  • public static ExecutorService newFixedThreadPool(int nThreads)
    创建固定数目线程的线程池。
  • public static ExecutorService newCachedThreadPool()
    创建一个可缓存的线程池,调用execute将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线 程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
  • public static ExecutorService newSingleThreadExecutor()
    创建一个单线程化的Executor。
  • public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
    创建一个支持延迟及周期性的任务执行的线程池,多数情况下可用来替代Timer类。

ExecutorService 使用方法:
这里有几种不同的方式让你将任务委托给壹個 ExecutorService。

  • execute(Runnable)

      executorService.execute(new Runnable() {  
          public void run() {  
              System.out.println("Asynchronous task");  
          }  
      });  
    
  • Future submit(Runnable)
    同样接收壹個 Runnable 的实现作为参数,但是会返回一個 Future 对象。这個 Future 对象可以用于判断 Runnable 是否结束执行。
    Future future = executorService.submit(new Runnable() {
    public void run() {
    System.out.println("Asynchronous task");
    }
    });
    //如果任务结束执行则返回 null
    System.out.println("future.get()=" + future.get());

  • Future submit(Callable)
    Callable 的 call() 方法可以返回壹個结果。Callable 的返回值可以从方法 submit(Callable) 返回的 Future 对象中获取。
    Future future = executorService.submit(new Callable(){
    public Object call() throws Exception {
    System.out.println("Asynchronous Callable");
    return "Callable Result";
    }
    });
    System.out.println("future.get() = " + future.get());

  • T invokeAny(Collection<Callable>)
    任务集合中,任何一个任务完成就返回。
    接收Callable 对象的集合作为参数。调用该方法不会返回 Future 对象,而是返回集合中某一個 Callable 对象的结果。
    无法保证调用之后返回的结果是哪個 Callable。
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    Set<Callable<String>> callables = new HashSet<Callable<String>>();
    callables.add(new Callable<String>() {
    public String call() throws Exception {
    return "Task 1";
    }
    });
    callables.add(new Callable<String>() {
    public String call() throws Exception {
    return "Task 2";
    }
    });
    callables.add(new Callable<String>() {
    public String call() throws Exception {
    return "Task 3";
    }
    });
    String result = executorService.invokeAny(callables);
    System.out.println("result = " + result);
    executorService.shutdown();

  • List<Future> invokeAll(Collection<Callable>)
    同步的方法,执行所有的任务列表,当所有任务都执行完成后,返回Future列表。

执行 Runnable 任务:
通过 Executors 的以上四个静态工厂方法获得 ExecutorService 实例,而后调用该实例的 execute(Runnable command)方法即可。一旦 Runnable 任务传递到 execute()方法,该方法便会自动在一个线程上执行。下面是 Executor 执行 Runnable 任务的示例代码:

import java.util.concurrent.ExecutorService;   
import java.util.concurrent.Executors;   

public class TestCachedThreadPool{   
    public static void main(String[] args){   
        ExecutorService executorService = Executors.newCachedThreadPool();   
//      ExecutorService executorService = Executors.newFixedThreadPool(5);  
//      ExecutorService executorService = Executors.newSingleThreadExecutor();  
        for (int i = 0; i < 5; i++){   
            executorService.execute(new TestRunnable());   
            System.out.println("************* a" + i + " *************");   
        }   
        executorService.shutdown();   
    }   
}   

class TestRunnable implements Runnable{   
    public void run(){   
        System.out.println(Thread.currentThread().getName() + "线程被调用了。");   
    }   
}

执行结果如下:


从结果中可以看出,pool-1-thread-1 和 pool-1-thread-2 均被调用了两次,这是随机的,execute 会首先在线程池中选择一个已有空闲线程来执行任务,如果线程池中没有空闲线程,它便会创建一个新的线程来执行任务。

ExecuteService 服务的关闭:
当使用 ExecutorService 完毕之后,我们应该关闭它。 例如:你的程序通过 main() 方法启动,并且主线程退出了你的程序,如果你还有壹個活动的 ExecutorService 存在于你的程序中,那么程序将会继续保持运行状态。存在于 ExecutorService 中的活动线程会阻止Java虚拟机关闭。
为了关闭在 ExecutorService 中的线程,你需要调用 ***shutdown() 方法。executorService.shutdown();ExecutorService 并不会马上关闭,而是不再接收新的任务,壹但所有的线程结束执行当前任务,ExecutorServie 才会真的关闭。所有在调用 shutdown() 方法之前提交到 ExecutorService 的任务都会执行。
如果你希望立即关闭 ExecutorService,你可以调用
shutdownNow() ***方法。executorService.shutdownNow();这個方法会尝试马上关闭所有正在执行的任务,并且跳过所有已经提交但是还没有运行的任务。但是对于正在执行的任务,是否能够成功关闭它是无法保证的。
awaitTermination方法,方法调用会被阻塞,直到所有任务执行完毕并且shutdown请求被调用,或者参数中定义的timeout时间到达,或者当前线程被打断,这几种情况任意一个发生了就会导致该方法的执行。接收timeout和TimeUnit两个参数,用于设定超时时间及单位。当等待超过设定时间时,会监测ExecutorService是否已经关闭,若关闭则返回true,否则返回false。(若超时未关闭,程序也继续往下进行。传入Long.MAX_VALUE, TimeUnit.DAYS参数,可确保子进程完成。)一般情况下会和shutdown方法组合使用。

// 关闭启动线程 
service.shutdown(); 
// 等待子线程结束,再继续执行下面的代码 
service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);  //这里表示近似永远等待
//service.awaitTermination(1, TimeUnit.MINUTES);//等待一分钟
//service.awaitTermination(2, TimeUnit.SECONDS);//两秒钟
System.out.println("all thread complete");

还有 service.isTerminated()service.isTerminating()service.isShutdown()等方法。


参考:
http://wiki.jikexueyuan.com/project/java-concurrency/executor.html
http://blog.csdn.net/bairrfhoinn/article/details/16848785
http://shift-alt-ctrl.iteye.com/blog/1841088

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容