同步I/O模型的弊端
===>每一个线程的创建都会消耗服务端内存,当大量请求进来,会耗尽内存,导致服务宕机
伪异步I/O的弊端分析
===>当对Socket的输入流进行读取操作的时候,它会一直阻塞下去,知道发生如下三件事情
(1)有数据可读
(2)可用数据已经读取完毕
(3)发生空指针或者I/O异常
===>这意味着当对方发送请求或应答消息比较缓慢,或者网络传输比较慢时候,读取输入流的一方的通信线程将被长时间阻塞。在阻塞期间,其他接入的消息只能在消息队列中排队。
===>伪异步I/O实际上仅仅只是对之前I/O线程模型的一个简单优化,它无法从根本上解决同步I/O导致的通信线程阻塞问题,下面我们简单分析下如果通信对方返回应答时间过长,会引起的级联鼓掌。
(1)服务端处理缓慢,返回应答消息耗费60s,平时只需要10ms
(2)采用伪异步I/O线程正在读取故障服务节点的响应,由于读取输入流是阻塞的。因此,它将会被同步阻塞60s
(3)假如所有的可用线程都被故障服务器阻塞,那后续所有的I/O消息都将在队列中排队。
(4)由于线程池采用阻塞队列实现,当队列积满之后,后续入队列的操作将被阻塞
(5)由于前端只有一个Accptor线程接收客户端接入,它被阻塞在线程池的同步阻塞队列之后,新的客户端请求消息将被拒绝,客户端会发生大量的连接超时。
(6)由于几乎所有的链接都超时,调用者会认为系统崩溃,无法接收新的请求消息。
【一】同步阻塞I/O服务端通信模型
第一:socket同步阻塞服务器的启动
1 package com.yeepay.sxf.testbio; 2 3 import java.io.IOException; 4 import java.net.ServerSocket; 5 import java.net.Socket; 6 7 /** 8 * 时间服务器 9 * 基于同步阻塞I/O实现的服务器模型 10 * @author sxf 11 * 12 */ 13 public class TimerServer { 14 15 /** 16 * 启动timerServer服务器 17 */ 18 public void init(){ 19 int port=8000; 20 //创建Socket服务 21 ServerSocket server=null; 22 try { 23 server=new ServerSocket(port); 24 System.out.println("TimerServer.init()===>the time server is start in port"+port); 25 Socket socket=null; 26 while(true){ 27 //获取一次socket请求 28 socket=server.accept(); 29 //启动一个新线程处理socket请求 30 new Thread(new TimerServerHandler(socket)).start(); 31 } 32 } catch (IOException e) { 33 e.printStackTrace(); 34 }finally{ 35 if(server!=null){ 36 try { 37 server.close(); 38 } catch (IOException e) { 39 // TODO Auto-generated catch block 40 e.printStackTrace(); 41 } 42 } 43 server=null; 44 } 45 46 } 47 48 49 public static void main(String[] args) { 50 //启动timerServer服务 51 TimerServer timerServer=new TimerServer(); 52 timerServer.init(); 53 } 54 }
第二:soket服务器接收到请求的处理类
1 package com.yeepay.sxf.testbio; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.io.PrintWriter; 7 import java.net.Socket; 8 import java.util.Date; 9 10 /** 11 * 时间服务器接受socket请求的处理类 12 * @author sxf 13 * 继承Runnable接口的线程类 14 * 15 */ 16 public class TimerServerHandler implements Runnable { 17 18 private Socket socket; 19 20 public TimerServerHandler(Socket socket) { 21 this.socket=socket; 22 } 23 24 /** 25 * 处理socket请求的线程体 26 */ 27 @Override 28 public void run() { 29 BufferedReader in=null; 30 PrintWriter out=null; 31 try { 32 //获取请求的输入流 33 in=new BufferedReader(new InputStreamReader(this.socket.getInputStream())); 34 //获取响应请求的输出流 35 out=new PrintWriter(this.socket.getOutputStream(),true); 36 37 String currentTime=null; 38 String body=null; 39 //读取请求输入流的内容获取请求信息 40 while(true){ 41 body=in.readLine(); 42 if(body==null){ 43 break; 44 } 45 //打印请求信息 46 System.out.println("TimerServerHandler.run()==>the time server receive order:"+body); 47 48 //处理请求信息 49 if("shangxiaofei".equals(body)){ 50 currentTime=new Date(System.currentTimeMillis()).toString(); 51 }else{ 52 currentTime="you is not get time"; 53 } 54 //响应请求信息 55 out.println(currentTime); 56 } 57 58 } catch (IOException e) { 59 e.printStackTrace(); 60 }finally{ 61 if(in!=null){ 62 try { 63 in.close(); 64 } catch (IOException e) { 65 // TODO Auto-generated catch block 66 e.printStackTrace(); 67 } 68 } 69 70 if(out!=null){ 71 out.close(); 72 } 73 74 if(this.socket!=null){ 75 try { 76 socket.close(); 77 } catch (IOException e) { 78 // TODO Auto-generated catch block 79 e.printStackTrace(); 80 } 81 } 82 83 this.socket=null; 84 } 85 86 87 88 89 } 90 91 }
第三:向socket服务器发送请求
1 package com.yeepay.sxf.testbio; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.io.PrintWriter; 7 import java.net.Socket; 8 9 /** 10 * 创建一个客户端请求 11 * @author sxf 12 * 13 */ 14 public class TimerClient { 15 16 17 18 public static void main(String[] args) { 19 int port=8000; 20 Socket socket=null; 21 BufferedReader in=null; 22 PrintWriter out=null; 23 try { 24 socket=new Socket("127.0.0.1",port); 25 in=new BufferedReader(new InputStreamReader(socket.getInputStream())); 26 out=new PrintWriter(socket.getOutputStream(),true); 27 //发送请求 28 out.println("shangxiaofei!="); 29 System.out.println("TimerClient.main()send order to server success"); 30 31 //等待服务器响应 32 String resp=in.readLine(); 33 System.out.println("TimerClient.main(Now is:)"+resp); 34 } catch (Exception e) { 35 // TODO Auto-generated catch block 36 e.printStackTrace(); 37 }finally{ 38 if(out!=null){ 39 out.close(); 40 out=null; 41 } 42 if(in !=null){ 43 try { 44 in.close(); 45 } catch (IOException e) { 46 // TODO Auto-generated catch block 47 e.printStackTrace(); 48 } 49 in=null; 50 } 51 52 if(socket!=null){ 53 try { 54 socket.close(); 55 } catch (IOException e) { 56 // TODO Auto-generated catch block 57 e.printStackTrace(); 58 } 59 } 60 } 61 } 62 63 }
【二】同步阻塞I/O服务端通信模型构造的伪异步通信模型
一:伪异步socket服务端启动(就是在同步的基础上使用了线程池)
1 package com.yeepay.sxf.testbio; 2 3 import java.io.IOException; 4 import java.net.ServerSocket; 5 import java.net.Socket; 6 7 /** 8 * 时间服务器 9 * 基于同步阻塞I/O实现的服务器模型 10 * @author sxf 11 * 12 */ 13 public class TimerServer { 14 15 /** 16 * 启动timerServer服务器 17 */ 18 public void init(){ 19 int port=8000; 20 //创建Socket服务 21 ServerSocket server=null; 22 try { 23 server=new ServerSocket(port); 24 System.out.println("TimerServer.init()===>the time server is start in port"+port); 25 Socket socket=null; 26 //创建处理socket请求的线程池 27 TimerServerHandlerExcetorPool pool=new TimerServerHandlerExcetorPool(50, 10000); 28 29 while(true){ 30 //获取一次socket请求 31 socket=server.accept(); 32 //将请求任务提交到线程池处理 33 pool.execute(new TimerServerHandler(socket)); 34 } 35 } catch (IOException e) { 36 e.printStackTrace(); 37 }finally{ 38 if(server!=null){ 39 try { 40 server.close(); 41 } catch (IOException e) { 42 // TODO Auto-generated catch block 43 e.printStackTrace(); 44 } 45 } 46 server=null; 47 } 48 49 } 50 51 52 public static void main(String[] args) { 53 //启动timerServer服务 54 TimerServer timerServer=new TimerServer(); 55 timerServer.init(); 56 } 57 }
二:伪异步socket服务处理socket请求的线程池
1 package com.yeepay.sxf.testbio; 2 3 import java.util.concurrent.ArrayBlockingQueue; 4 import java.util.concurrent.ExecutorService; 5 import java.util.concurrent.ThreadPoolExecutor; 6 import java.util.concurrent.TimeUnit; 7 /** 8 * 处理socket服务器接收到的socket请求的线程池 9 * @author sxf 10 * 11 */ 12 public class TimerServerHandlerExcetorPool { 13 14 private ExecutorService executorService; 15 16 /** 17 * 初始化线程池 18 * @param maxPoolSize 19 * @param queueSize 20 */ 21 public TimerServerHandlerExcetorPool(int maxPoolSize,int queueSize){ 22 executorService=new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), maxPoolSize, 120L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(queueSize)); 23 } 24 25 /** 26 * 提交到线程池,执行socket请求任务 27 * @param runnable 28 */ 29 public void execute(Runnable runnable){ 30 executorService.execute(runnable); 31 } 32 33 }
三:处理请求的Handler类(线程类)
1 package com.yeepay.sxf.testbio; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.io.PrintWriter; 7 import java.net.Socket; 8 import java.util.Date; 9 10 /** 11 * 时间服务器接受socket请求的处理类 12 * @author sxf 13 * 继承Runnable接口的线程类 14 * 15 */ 16 public class TimerServerHandler implements Runnable { 17 18 private Socket socket; 19 20 public TimerServerHandler(Socket socket) { 21 this.socket=socket; 22 } 23 24 /** 25 * 处理socket请求的线程体 26 */ 27 @Override 28 public void run() { 29 BufferedReader in=null; 30 PrintWriter out=null; 31 try { 32 //获取请求的输入流 33 in=new BufferedReader(new InputStreamReader(this.socket.getInputStream())); 34 //获取响应请求的输出流 35 out=new PrintWriter(this.socket.getOutputStream(),true); 36 37 String currentTime=null; 38 String body=null; 39 //读取请求输入流的内容获取请求信息 40 while(true){ 41 body=in.readLine(); 42 if(body==null){ 43 break; 44 } 45 //打印请求信息 46 System.out.println("TimerServerHandler.run()==>the time server receive order:"+body); 47 48 //处理请求信息 49 if("shangxiaofei".equals(body)){ 50 currentTime=new Date(System.currentTimeMillis()).toString(); 51 }else{ 52 currentTime="you is not get time"; 53 } 54 //响应请求信息 55 out.println(currentTime); 56 } 57 58 } catch (IOException e) { 59 e.printStackTrace(); 60 }finally{ 61 if(in!=null){ 62 try { 63 in.close(); 64 } catch (IOException e) { 65 // TODO Auto-generated catch block 66 e.printStackTrace(); 67 } 68 } 69 70 if(out!=null){ 71 out.close(); 72 } 73 74 if(this.socket!=null){ 75 try { 76 socket.close(); 77 } catch (IOException e) { 78 // TODO Auto-generated catch block 79 e.printStackTrace(); 80 } 81 } 82 83 this.socket=null; 84 } 85 86 87 88 89 } 90 91 }
四:客户端发送请求
1 package com.yeepay.sxf.testbio; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.io.PrintWriter; 7 import java.net.Socket; 8 9 /** 10 * 创建一个客户端请求 11 * @author sxf 12 * 13 */ 14 public class TimerClient { 15 16 17 18 public static void main(String[] args) { 19 int port=8000; 20 Socket socket=null; 21 BufferedReader in=null; 22 PrintWriter out=null; 23 try { 24 socket=new Socket("127.0.0.1",port); 25 in=new BufferedReader(new InputStreamReader(socket.getInputStream())); 26 out=new PrintWriter(socket.getOutputStream(),true); 27 //发送请求 28 out.println("shangxiaofei!="); 29 System.out.println("TimerClient.main()send order to server success"); 30 31 //等待服务器响应 32 String resp=in.readLine(); 33 System.out.println("TimerClient.main(Now is:)"+resp); 34 } catch (Exception e) { 35 // TODO Auto-generated catch block 36 e.printStackTrace(); 37 }finally{ 38 if(out!=null){ 39 out.close(); 40 out=null; 41 } 42 if(in !=null){ 43 try { 44 in.close(); 45 } catch (IOException e) { 46 // TODO Auto-generated catch block 47 e.printStackTrace(); 48 } 49 in=null; 50 } 51 52 if(socket!=null){ 53 try { 54 socket.close(); 55 } catch (IOException e) { 56 // TODO Auto-generated catch block 57 e.printStackTrace(); 58 } 59 } 60 } 61 } 62 63 }