本文共 3688 字,大约阅读时间需要 12 分钟。
JavaSE5的java.util.concurrent包中的执行器(Executor)将为你管理Thread对象,从而简化了并发编程。Executor在客户端和任务执行之间提供了一个间接层;与客户端直接执行任务不同,这个中介对象将执行任务。Executor允许你管理异步任务的执行,而无须显式地管理线程的生命周期。Executor在JavaSe5/6中是启动任务的优选方法。
如果程序中创建了大量的生命周期很短的线程,应该使用线程池。一个线程池中包含许多准备运行的空闲线程。将Runnable对象交给线程池,就会有一个线程调用run()方法。当run()方法退出时,线程不会死亡,而是在池中准备为下一个请求提供服务。
另一个使用线程池的理由是减少并发线程的数目。创建大量线程会大大降低性能甚至使虚拟机崩溃。如果有一个会创建许多多线程的算法,应该使用一个线程数“固定的”线程池以限制并发线程的总数。
执行器(Executors)类有许多静态工厂方法用来构建线程池,下面的表对这些方法进行了汇总:
方法 | 描述 |
newFixedThreadPool | 该池包含固定数量的线程,空闲线程会被一直保留 |
newCachedThreadPool | 必要时创建新线程,空闲线程会被保留60秒 |
newSingleThreadPool | 只有一个线程的线程池,该线程顺序执行每一个提交的任务(类似于Swing事件分配线程) |
newScheduledThreadPool | 用于预定执行而构建的固定线程池,替代java.util.Timer |
newSingleThreadScheduledPool | 用于预定执行而构建的单线程池 |
我们可以使用Executor来代替在MoreBasicThreads.java中显示地创建Thread对象,LiftOff对象知道如何运行具体的任务,与命令设计模式一样,它暴露了要执行的单一方法。ExecutorService(具有服务生命周期的Executor,例如关闭)知道如何构建恰当的上下文来执行Runnable对象。在下面的示例中,CachedThreadPool将为每个任务都创建一个线程。注意,ExecutorService对象是使用静态的Executor方法创建的,这个方法可以确定其Executor类型。
测试CachedThreadPool:
package chapter21;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * 测试CachedThreadPool */public class CachedThreadPool { public static void main(String[] args) { //根据需要创建线程 ExecutorService exec = Executors.newCachedThreadPool(); for(int i =0; i < 5; i ++) {
//LiftOff参见前一篇博客 exec.execute(new LiftOff());//将任务放入线程池中执行}//当所有线程执行完成后,关闭线程池exec.shutdown();}} 运行结果: #0(9), #3(9), #2(9), #1(9), #4(9), #3(8), #0(8), #4(8), #3(7), #0(7), #4(7), #1(8), #2(8), #1(7), #2(7), #1(6), #2(6), #3(6), #1(5), #0(6), #2(5), #0(5), #3(5), #4(6), #2(4), #1(4), #0(4), #2(3), #3(4), #0(3), #3(3), #0(2), #3(2), #0(1), #3(1), #0(LiftOff!), #3(LiftOff!), #1(3), #4(5), #2(2), #1(2), #1(1), #4(4), #2(1), #1(LiftOff!), #4(3), #4(2), #4(1), #2(LiftOff!), #4(LiftOff!), 测试FixedThreadPool: package chapter21;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * 测试FixedThreadPool */public class FixedThreadPoolTest { public static void main(String[] args) { //创建一个有5个线程的线程池 ExecutorService exec = Executors.newFixedThreadPool(5); for(int i = 0; i < 5; i ++) { exec.execute(new LiftOff()); } //当所有的任务执行完毕后,关闭线程池 exec.shutdown(); }} 执行结果: #0(9), #0(8), #0(7), #0(6), #0(5), #0(4), #0(3), #0(2), #0(1), #0(LiftOff!), #1(9), #1(8), #1(7), #1(6), #1(5), #1(4), #1(3), #1(2), #1(1), #1(LiftOff!), #2(9), #2(8), #2(7), #2(6), #2(5), #2(4), #2(3), #2(2), #2(1), #2(LiftOff!), #3(9), #3(8), #3(7), #3(6), #3(5), #3(4), #3(3), #3(2), #3(1), #3(LiftOff!), #4(9), #4(8), #4(7), #4(6), #4(5), #4(4), #4(3), #4(2), #4(1), #4(LiftOff!), SingleThreadExecutor就像是线程数量为1的FixedThreadPool。这对于你希望在另一个线程里持续运行的任何事物(长期存活的任务)来说,都是很有用的,例如监听进入的套接字连接的任务,它对于希望在线程中运行的短任务也同样很方便,例如,更新本地或远程日志的小任务或者事件分发线程。 如果向SingleThreadExecutor提交了多个任务,那么这些任务将排队,每个任务都会在下一个任务开始之前运行结束,所有的任务将使用相同的线程。在下面的示例中,你可以看到每个任务都是按照它们被提交的顺序,并且是在下一个任务开始之前完成的。因此,SingleThreadExecutor会序列化所有交给它的任务,并会维护它自己(隐藏)的悬挂任务队列。 下面演示SingleThreadPool: package chapter21;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * 测试SingleThreadExecutor */public class SingleThreadExecutorTest { public static void main(String[] args) { ExecutorService exec = Executors.newSingleThreadExecutor(); for(int i = 0; i < 5; i ++) { exec.execute(new LiftOff()); } //当所有任务执行完毕后,关闭线程池 exec.shutdown(); }} 运行结果: #0(9), #0(8), #0(7), #0(6), #0(5), #0(4), #0(3), #0(2), #0(1), #0(LiftOff!), #1(9), #1(8), #1(7), #1(6), #1(5), #1(4), #1(3), #1(2), #1(1), #1(LiftOff!), #2(9), #2(8), #2(7), #2(6), #2(5), #2(4), #2(3), #2(2), #2(1), #2(LiftOff!), #3(9), #3(8), #3(7), #3(6), #3(5), #3(4), #3(3), #3(2), #3(1), #3(LiftOff!), #4(9), #4(8), #4(7), #4(6), #4(5), #4(4), #4(3), #4(2), #4(1), #4(LiftOff!),
转载地址:http://fklvb.baihongyu.com/