zoukankan      html  css  js  c++  java
  • java多线程(三)-Executors实现的几种线程池以及Callable

    从java5开始,类库中引入了很多新的管理调度线程的API,最常用的就是Executor(执行器)框架。Executor帮助程序员管理Thread对象,简化了并发编程,它其实就是在 提供了一个中间层,方便程序员管理异步任务的执行,而又不用显式的管理线程的生命周期。


    Executor采用了线程池实现,也更节约开销,因为是我们启动新线程的首选方法。

    示例代码:src/thread_runnable/CachedThreadPool.java

     1 public class CachedThreadPool{
     2     
     3     public static void main(String[] args) {
     4         ExecutorService exec = Executors.newCachedThreadPool();
     5         
     6         
     7         System.out.println("main start  "  + Thread.currentThread().getName());
     8         for (int i=0; i<3; i++){
     9             exec.execute(new CountDown());
    10         }
    11         
    12         exec.shutdown();
    13         System.out.println("main end  "  + Thread.currentThread().getName());
    14     }
    15 
    16 }

    输出结果:(每次执行输出结果都有差异)

    Executors类通过提供一系列的工厂方法来创建线程池,返回的线程池都实现了ExecutorService接口,ExecutorService接口实现了Executor接口,提供了更丰富的方法来管理线程池,ExecutorService对象可以通过execute(Runnable)/submit(Callable)方法来开始执行新的方法(这本身也属于命令设计模式)。

    ExecutorService(其实就是线程池)的生命周期包括三种状态,运行,关闭,终止。创建后便进入运行状态。调用shutdown()方法就进入关闭状态。此时ExecutorService不再接受新的任务,但是它还在执行已经提交的任务,等到所有的任务都执行完毕后,就到了终止状态。


    Executors类通过提供一系列的工厂方法来创建线程池,常见类型如下:

    1 public static ExecutorService newFixedThreadPool(int nThreads)

    创建固定数目的线程池

    1 public static ExecutorService newCachedThreadPool()

    创建一个可缓存的线程池,调用execute添加新任务后,如果有之前构造的可用线程,则重用该线程;否则,就创建一个新线程并添加到池中。并且可以从缓存中移除那些60s未被使用的线程。

    1 public static ExecutorService newSingleThreadExecutor()

    创建一个单线程的线程池。其实只有一个线程,所有的任务按照指定的顺序,(FIFO,LIFO,优先级)来执行。

    1 public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

    创建一个定长线程池,支持定时及周期性的任务执行,所以很多时候可用来代替Timer类。

    看一个简单的例子,代码地址:src/thread_runnable/FixedThreadPool.java

     1 public class FixedThreadPool{
     2     public static void main(String[] args) {
     3         int ThreadCount = 2;    
     4         ExecutorService exec = Executors.newFixedThreadPool(ThreadCount);
     5         
     6         System.out.println("main start  "  + Thread.currentThread().getName());
     7         for (int i=0; i<3; i++){
     8             exec.execute(new CountDown());
     9         }
    10         exec.shutdown();
    11         System.out.println("main end  "  + Thread.currentThread().getName());
    12         
    13     }
    14 }

    当ThreadCount = 2时,某一次输出结果为:

    从输出结果可以看出,在最初的时候,只有thread-1和thread-2两个线程在执行任务,当之前的任务执行完成之后,thread-2被复用,开始执行第三个任务。
    那么我们可以想象,如果我们把 让ThreadCount = 1,那么应该只存在一个线程,其执行完一个任务,再接着执行另一个。
    修改ThreadCount = 1,输出结果符合我们的预期:

    可以周期或者delay执行的 线程也是在实际项目中也是比较常见的。
    示例代码地址:src hread_runnableScheduledExecutorServiceDemo.java

     1 public class ScheduledExecutorServiceDemo {
     2     public static void main(String[] args) {
     3         // TODO Auto-generated method stub
     4         ScheduledExecutorService mScheduledService  = Executors.newScheduledThreadPool(2);
     5         System.out.println("ScheduledExecutorServiceDemo --- main start, " + Thread.currentThread().getName());
     6         mScheduledService.schedule(new CountDown(), 2 , TimeUnit.SECONDS);
     7         System.out.println("ScheduledExecutorServiceDemo --- main end, " + Thread.currentThread().getName());
     8         mScheduledService.shutdown();
     9     }
    10 }

    输出结果:(通过实际输出,可以看到 ,两秒钟之后,才开始执行任务当中的打印 语句)

    关于周期性任务的demo。
    示例代码地址:src hread_runnableScheduledFixedServiceDemo_2.java

     1 public class ScheduledFixedServiceDemo_2 {
     2     public static void main(String[] args) {
     3         // TODO Auto-generated method stub
     4         ScheduledExecutorService mScheduledService  = Executors.newScheduledThreadPool(2);
     5         System.out.println("ScheduledFixedServiceDemo_2 --- main start, " + Thread.currentThread().getName());
     6         mScheduledService.scheduleWithFixedDelay(new Runnable() {
     7             int count = 0;
     8             @Override
     9             public void run() {
    10                 System.out.println("fixed print = " + count++);
    11                 
    12             }
    13         }, 1, 2 , TimeUnit.SECONDS);
    14         System.out.println("ScheduledFixedServiceDemo_2 --- main end, " + Thread.currentThread().getName());
    15     }
    16 }

    输出结果:

    …..后面每间隔2s,输出一次。

    Runnable虽然执行任务,但是没有返回值,而java 5之后 ,重新引入了一个 Callable接口,它是一个具有类型参数的泛型,表示从call()方法中返回的值。不过需要注意的是,把Callable对象传递给ExecutorService的submit方法后,在新线程上执行的call()方法返回的其实是 Future对象,Future对象有isDone(),get()等方法来判断是否完成,以及得到返回值等。

    代码地址:src hread_runnableCallableDemo.java

     1 class TaskWithResult implements Callable<String> {
     2     public String call() throws Exception {        
     3         return "result of TaskWithResult from Callable "  + "	 " + Thread.currentThread().getName();
     4     }
     5 }
     6 
     7 
     8 public class CallableDemo {
     9     public static void main(String[] args) {
    10         // TODO Auto-generated method stub
    11         ExecutorService exec = Executors.newCachedThreadPool();
    12         
    13         System.out.println("main  start	" + Thread.currentThread().getName());
    14         Future<String> fs = exec.submit(new TaskWithResult());
    15         exec.shutdown();
    16         
    17         try {
    18             //当callable对象并没有完成时,这里一直是堵塞的。
    19             System.out.println(fs.get());
    20         } catch (Exception e) {
    21             e.printStackTrace();
    22         }
    23         System.out.println("main  end	" + Thread.currentThread().getName());
    24     }    
    25 }


    输出结果:

    这几篇java多线程文章的demo代码下载地址 http://download.csdn.net/detail/yaowen369/9786452

    -------
    作者: www.yaoxiaowen.com
    github: https://github.com/yaowen369

  • 相关阅读:
    内联元素间的间隔
    事件处理程序DOM0,DOM2,IE的区别总结
    open live writer下载安装
    sublime3下载安装及常用插件、浏览器预览设置
    常用的清除浮动的方法
    input中的name,value以及label中的for
    利用fiddler将本地网页放到某个域下
    Date类型常用概念及方法总结(1)
    构建之法 第六章 敏捷流程
    javascript 入门之 新窗口打开网站
  • 原文地址:https://www.cnblogs.com/yaoxiaowen/p/6576851.html
Copyright © 2011-2022 走看看