如例程3-8所示,EchoServer利用线程池ThreadPool来完成与客户的通信任务。
例程3-8 EchoServer.java(使用线程池ThreadPool类)
package multithread2;
import java.io.*;
import java.net.*;
public class EchoServer {
private int port=8000;
private ServerSocket serverSocket;
private ThreadPool threadPool; //线程池
private final int POOL_SIZE=4; //单个CPU时线程池中工作线程的数目
public EchoServer() throws IOException {
serverSocket = new ServerSocket(port);
//创建线程池
//Runtime的availableProcessors()方法返回当前系统的CPU的数目
//系统的CPU越多,线程池中工作线程的数目也越多
threadPool= new ThreadPool(
Runtime.getRuntime().availableProcessors() * POOL_SIZE);
System.out.println("服务器启动");
}
public void service() {
while (true) {
Socket socket=null;
try {
socket = serverSocket.accept();
threadPool.execute(new Handler(socket)); //把与客户通信的任务交给线程池
}catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String args[])throws IOException {
new EchoServer().service();
}
}
/** 负责与单个客户通信的任务,代码与3.6.1节的例程3-5的Handler类相同 */
class Handler implements Runnable{…}
在以上EchoServer的service()方法中,每接收到一个客户连接,就向线程池ThreadPool提交一个与客户通信的任务。ThreadPool把任务加入到工作队列中,工作线程会在适当的时候从队列中取出这个任务并执行它。
3.6.3 使用JDK类库提供的线程池
java.util.concurrent包提供了现成的线程池的实现,它比3.6.2节介绍的线程池更加健壮,而且功能也更强大。如图3-4所示是线程池的类框图。
图3-4 JDK类库中的线程池的类框图
Executor接口表示线程池,它的execute(Runnable task)方法用来执行Runnable类型的任务。Executor的子接口ExecutorService中声明了管理线程池的一些方法,比如用于关闭线程池的shutdown()方法等。Executors类中包含一些静态方法,它们负责生成各种类型的线程池ExecutorService实例,如表3-1所示。
表3-1 Executors类生成的ExecutorService实例的静态方法
Executors类的静态方法
创建的ExecutorService线程池的类型
newCachedThreadPool()
在有任务时才创建新线程,空闲线程被保留60秒
newFixedThreadPool(int nThreads)
线程池中包含固定数目的线程,空闲线程会一直保留。参数nThreads设定线程池中线程的数目
newSingleThreadExecutor()
线程池中只有一个工作线程,它依次执行每个任务
newScheduledThreadPool(int corePoolSize)
线程池能按时间计划来执行任务,允许用户设定计划执行任务的时间。参数corePoolSize设定线程池中线程的最小数目。当任务较多时,线程池可能会创建更多的工作线程来执行任务
newSingleThreadScheduledExecutor()
线程池中只有一个工作线程,它能按时间计划来执行任务
如例程3-9所示,EchoServer就利用上述线程池来负责与客户通信的任务。
例程3-9 EchoServer.java(使用java.util.concurrent包中的线程池类)
package multithread3;
import java.io.*;
import java.net.*;
import java.util.concurrent.*;
public class EchoServer {
private int port=8000;
private ServerSocket serverSocket;
private ExecutorService executorService; //线程池
private final int POOL_SIZE=4; //单个CPU时线程池中工作线程的数目
public EchoServer() throws IOException {
serverSocket = new ServerSocket(port);
//创建线程池
//Runtime的availableProcessors()方法返回当前系统的CPU的数目
//系统的CPU越多,线程池中工作线程的数目也越多
executorService= Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors() * POOL_SIZE);
System.out.println("服务器启动");
}
public void service() {
while (true) {
Socket socket=null;
try {
socket = serverSocket.accept();
executorService.execute(new Handler(socket));
}catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String args[])throws IOException {
new EchoServer().service();
}
}
/** 负责与单个客户通信的任务,代码与3.6.1节的例程3-5的Handler类相同 */
class Handler implements Runnable{…}
在EchoServer的构造方法中,调用Executors.newFixedThreadPool()创建了具有固定工作线程数目的线程池。在EchoServer的service()方法中,通过调用executor- Service.execute()方法,把与客户通信的任务交给了ExecutorService线程池来执行。
内容导航