多任务处理:管理调度Executor 接口

系统管理调度:Executor接口

 在上一节中我们已经看到,将客户服务器协议的细节封装起来(如EchoProtocol.java),就可以通过同一个协议实现来使用不同的"调度"方法(如,TCPEchoServerThread.javaTCPEchoServerThreadPool.java)。实际上,对于调度方法本身来说也是这样。Executor接口java.util.concurrent包的一部分)就代表了一个根据某种策略来执行Runnable实例的对象,其中可能包括了排队和调度的细节,或如何选择要执行的任务。Executor接口只定义了一个方法:

interface Executor {

void execute(Runnable task);

}

Java提供了大量的内置Executor接口实现,它们都可以简单方便地使用,也可以进行扩展性的配置。其中一些还提供了处理维护线程等繁琐细节的功能。例如,如果一个线程因为未捕获的异常或其他故障停止,它们就自动创建一个新的线程来替换原来的线程。 

ExecutorService接口继承于Executor接口,并提供了一个更高级的工具来关闭服务器,包括正常的关闭和突然的关闭。ExecutorService还允许在完成任务后返回一个结果,这需要用到Callable接口,它和Runnable接口很像,只是多了一个返回值。

 我们可以通过调用Executors类的各种静态工厂方法来获取ExecutorService实例。示例程序TCPEchoServerExecutor.java演示了基本Executor工具的使用方法。

TCPEchoServerExecutor.java

0 import java.io.IOException;

1 import java.net.ServerSocket;

2 import java.net.Socket;

3 import java.util.concurrent.Executor;

4 import java.util.concurrent.Executors;

5 import java.util.logging.Logger;

6

7 public class TCPEchoServerExecutor {

8

9 public static void main(String[] args) throws

IOException {

10

11 if (args.length != 1) { // Test for correct # of args

12 throw new IllegalArgumentException("Parameter(s):

<Port>");

13 }

14

15 int echoServPort = Integer.parseInt(args[0]); // Server

port

16

17 // Create a server socket to accept client connection

requests

18 ServerSocket servSock = new

ServerSocket(echoServPort);

19

20 Logger logger = Logger.getLogger("practical");

21

22 Executor service = Executors.newCachedThreadPool(); //

Dispatch svc

23

24 // Run forever, accepting and spawning a thread for each

connection

25 while (true) {

26 Socket clntSock = servSock.accept(); // Block waiting

for connection

27 service.execute(new EchoProtocol(clntSock, logger));

28 }

29 /* NOT REACHED */

30 }

31 }

TCPEchoServerExecutor.java 

1.设置:第11-20

端口号是唯一的参数。与前面的例子一样,我们要创建ServerSocket实例和Logger例。这里它们不必声明为常量,因为我们不需要用匿名的Thread子类。

2.获取一个Executor实例:第22

Executors类的newCachedThreadPool()静态工厂方法创建了一个ExecutorService实例。在使用一个实现了Runnable接口的实例调用它的execute()方法时,如果必要它将创建一个新的线程来处理任务。然而,它首先会尝试使用已有的线程。如果一个线程空闲了60秒以上,则将移出线程池。这个策略几乎总是比前面两个TCPEchoServer*例子的效率高。

3.反复循环,接收并执行连接:第25-28

当一个新的连接请求到来时,将创建一个新的EchoProtocol实例并传递给serviceexecute()方法,该方法要么将其分配给一个已有的线程,要么创建一个新的线程来处理它。值得注意的是,当达到稳定状态时,缓存线程池服务最终将保持合适的线程数,以使每个线程都保持忙碌,同时又很少创建或销毁线程。

只要有一个设计为使用Executor来调度客户端的服务器,我们就可以通过简单地改变Executor实例的类型来实现不同的调度策略。例如,如果我们想使用像TCPEchoServerPool.java中那样的固定大小的线程池,只需要改变与设置调度服务相关的一行代码:

Executor service =Executors.newFixedThreadPool(threadPoolSize); 

我们可以将线程池的大小设为1,转换成使用单一线程处理所有的客户端连接,或者使用以下方法来实现:

Executor service = Executors.newSingleThreadExecutor();

Executor方法中,如果一个"工人"线程由于某些故障死掉了,Executor将创建一个新的线程来代替它。而且,任务是在            Executor    的内部排队,而不是像我们最初的服务器那样在网络系统中排队。到现在为止,我们仅仅触及到了Java并发包的表层功能而已。

 

相关下载:

Java_TCPIP_Socket编程(doc)

http://download.csdn.net/detail/undoner/4940239

 

文献来源:

UNDONER(小杰博客) :http://blog.csdn.net/undoner

LSOFT.CN(琅软中国) :http://www.lsoft.cn

 

posted on 2012-12-23 09:47  吴一达  阅读(195)  评论(0编辑  收藏  举报

导航