1.为什么使用线程池
如果每当建立连接就创建一个新线程,然后在新线程中为连接处理交互。这种处理方式有以下不足之处:1.创建新线程在创建和销毁线程上花费的时间和消耗的系统资源开销很大;2.除了创建和销毁线程的开销之外,活动的线程也消耗系统资源;3. JVM 里创建太多的线程可能会导致系统由于过度消耗内存而用完内存或“切换过度”。
如果使用线程池,在程序一开始的时候就创建一定量的线程,这样减少了每次线程创建而带来的不必要时间耗损。这样,就可以立即为此次连接进行服务,使应用程序响应更快。而且,通过适当地调整线程池中的线程数目,也就是当请求的数目超过某个阈值时,就强制其它任何新到的请求一直等待,直到获得一个线程来处理为止,从而可以防止资源不足。
2.线程池服务端
此次服务端代码是对文章Socket编程(二)—TCP简单实例中服务端的修改,唯一不同就是通过线程池的方式来实现客户端的连接,客户端代码直接使用上面文章中的就行。
public class DatePoolServer {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(50);// 创建50大小的线程池
try (ServerSocket server = new ServerSocket(7456)) {
while (true) {
Socket connection = server.accept();
Callable<Void> task = new DateTask(connection);
pool.submit(task);//将任务提交到线程池,等待调用
}
} catch (IOException e) {
e.printStackTrace();
}
}
//发送日期的任务
private static class DateTask implements Callable<Void> {
private Socket connection;
public DateTask(Socket connection) {
this.connection = connection;
}
@Override
public Void call() {//在此任务被调用的是调用此方法
Writer writer;
try {//下面代码同之前文章中一致
writer = new OutputStreamWriter(connection.getOutputStream());
Date now = new Date();
writer.write(now.toString() + "\r\n");
writer.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (connection != null)
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
}