java executors api_java多线程(三)-Executors实现的几种线程池以及Callable

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

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

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

1 public classCachedThreadPool{2

3 public static voidmain(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(newCountDown());10 }11

12 exec.shutdown();13 System.out.println("main end " +Thread.currentThread().getName());14 }15

16 }

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

6992f0832e7a5d58b385098219d2b900.png

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 classFixedThreadPool{2 public static voidmain(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(newCountDown());9 }10 exec.shutdown();11 System.out.println("main end " +Thread.currentThread().getName());12

13 }14 }

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

f02b3506326771dfc65526f382dd071b.png

从输出结果可以看出,在最初的时候,只有thread-1和thread-2两个线程在执行任务,当之前的任务执行完成之后,thread-2被复用,开始执行第三个任务。

那么我们可以想象,如果我们把 让ThreadCount = 1,那么应该只存在一个线程,其执行完一个任务,再接着执行另一个。

修改ThreadCount = 1,输出结果符合我们的预期:

fe0a0f926e42d370c8376392856dfc29.png

可以周期或者delay执行的 线程也是在实际项目中也是比较常见的。

示例代码地址:src\thread_runnable\ScheduledExecutorServiceDemo.java

1 public classScheduledExecutorServiceDemo {2 public static voidmain(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 }

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

899a2510ea2edfafaf0a46de44eaef0e.png

关于周期性任务的demo。

示例代码地址:src\thread_runnable\ScheduledFixedServiceDemo_2.java

1 public classScheduledFixedServiceDemo_2 {2 public static voidmain(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(newRunnable() {7 int count = 0;8 @Override9 public voidrun() {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 }

输出结果:

3989c82535bb9ee226dce0ce001c4791.png

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

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

代码地址:src\thread_runnable\CallableDemo.java

1 class TaskWithResult implements Callable{2 public String call() throwsException {3 return "result of TaskWithResult from Callable " + "\t " +Thread.currentThread().getName();4 }5 }6

7

8 public classCallableDemo {9 public static voidmain(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 fs = exec.submit(newTaskWithResult());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 }

输出结果:

25eefd802650705d4f84b42bfd7b947e.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值