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\thread_runnable\ScheduledExecutorServiceDemo.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\thread_runnable\ScheduledFixedServiceDemo_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\thread_runnable\CallableDemo.java
1 class TaskWithResult implements Callable<String> { 2 public String call() throws Exception { 3 return "result of TaskWithResult from Callable " + "\t " + 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\t" + 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\t" + Thread.currentThread().getName()); 24 } 25 }
输出结果:
这几篇java多线程文章的demo代码下载地址 http://download.csdn.net/detail/yaowen369/9786452
-------
作者: www.yaoxiaowen.com
github: https://github.com/yaowen369