BIO编程
在实际的工作开发中,传统的模型有client/service模型。client端和service端要进行通信的话,有一种套接字的方式。传统的socket编程,包含一个socket服务端和一到多个socket客户端。在连接过程中,sokcetServer 绑定一个端口进行监听。client端通过ip地址和端口号对服务进行访问。在服务进入到service端后,service端新建一个线程。线程对请求进行相应的处理,处理完毕后,将处理结果返回给client端。在处理过程中,连接client阻塞。
代码实现:
server端代码:
Server 类
ServerHandler类,业务处理类
client端代码:
Client类
优点:传统的BIO模型进行通信,代码可读性比较强,理解容易。运行中,server端通过主线程监听accpet()方法阻塞式获取server的消息。
缺点:该模型最大的问题是,每一个client端访问都对应一个后台的线程,使得系统不具备弹性伸缩能力。一旦client请求过多,线程数会迅速膨胀,系统性能会急剧下降,导致堆栈溢出,进程宕机等问题的发生。
为了改进线程数过多,导致系统宕机的问题,同时也为了解决创建线程的消耗问题。后来又演进出了一种通过线程池或者消息队列实现1个或者多个线程处理N个客户端的模型,由于它的底层通信机制依然使用同步阻塞IO,所以被称为 “伪异步”。其原理就是在原来的service上新增一个线程池,将处理业务的线程通过线程池进行管理。如果线程数量到达上限时,将请求先存入queue中进行缓冲。具体代码如下:
client端代码不变。
server端:
1 import java.io.BufferedReader;
2 import java.io.PrintWriter;
3 import java.net.ServerSocket;
4 import java.net.Socket;
5
6 public class Server {
7
8 final static int PORT = 8765;
9
10 public static void main(String[] args) {
11 ServerSocket server = null;
12 BufferedReader in = null;
13 PrintWriter out = null;
14 try {
15 server = new ServerSocket(PORT);
16 System.out.println("server start");
17 Socket socket = null;
18 HandlerExecutorPool executorPool = new HandlerExecutorPool(50, 50);
19 while(true){
20 socket = server.accept();
21
22 executorPool.execute(new ServerHandler(socket));
23
24 }
25
26 } catch (Exception e) {
27 e.printStackTrace();
28 } finally {
29 if(in != null){
30 try {
31 in.close();
32 } catch (Exception e1) {
33 e1.printStackTrace();
34 }
35 }
36 if(out != null){
37 try {
38 out.close();
39 } catch (Exception e2) {
40 e2.printStackTrace();
41 }
42 }
43 if(server != null){
44 try {
45 server.close();
46 } catch (Exception e3) {
47 e3.printStackTrace();
48 }
49 }
50 server = null;
51 }
52
53
54
55 }
56
57
58 }
Server类
1 import java.util.concurrent.ArrayBlockingQueue;
2 import java.util.concurrent.ThreadPoolExecutor;
3 import java.util.concurrent.TimeUnit;
4
5
6 public class HandlerExecutorPool {
7 private ArrayBlockingQueue queue ;
8 private ThreadPoolExecutor executor;
9 public HandlerExecutorPool(int maxPoolSize, int queueSize){
10 queue = new ArrayBlockingQueue<Runnable>(queueSize);
11 this.executor = new ThreadPoolExecutor(
12 5,
13 maxPoolSize,
14 120L,
15 TimeUnit.SECONDS,
16 queue);
17 }
18
19 public void execute(Runnable task){
20 System.out.println("corePoolSize== "+executor.getCorePoolSize());
21 System.out.println("queuesize=="+queue.size());
22 this.executor.execute(task);
23
24 System.out.println("当前运行线程== "+executor.getLargestPoolSize());
25 System.out.println("queuesize=="+queue.size());
26 }
27
28
29
30 }
HandlerExecutorPool 线程池缓冲队列类
1 import java.io.BufferedReader;
2 import java.io.InputStreamReader;
3 import java.io.PrintWriter;
4 import java.net.Socket;
5 import java.util.concurrent.TimeUnit;
6
7 public class ServerHandler implements Runnable {
8
9 private Socket socket;
10 public ServerHandler (Socket socket){
11 this.socket = socket;
12 }
13
14 @Override
15 public void run() {
16 BufferedReader in = null;
17 PrintWriter out = null;
18 try {
19 Thread.currentThread().sleep(1000);
20 in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
21 out = new PrintWriter(this.socket.getOutputStream(), true);
22 String body = null;
23 while(true){
24 body = in.readLine();
25 if(body == null) break;
26 System.out.println("Server:" + body);
27 out.println("Server response");
28 }
29 } catch (Exception e) {
30 e.printStackTrace();
31 } finally {
32 if(in != null){
33 try {
34 in.close();
35 } catch (Exception e1) {
36 e1.printStackTrace();
37 }
38 }
39 if(out != null){
40 try {
41 out.close();
42 } catch (Exception e2) {
43 e2.printStackTrace();
44 }
45 }
46 if(socket != null){
47 try {
48 socket.close();
49 } catch (Exception e3) {
50 e3.printStackTrace();
51 }
52 }
53 socket = null;
54 }
55
56
57 }
58
59 }
ServerHandler类,业务处理类
这样改造后,有效的缓解了server端线程数过多时宕机的问题,但是依然没有解决阻塞的问题。依然会出现请求过多时,前台等待超时的问题。
最新文章
- jquery学习笔记---this关键字
- Leetcode 205 Isomorphic Strings 字符串处理
- Python开发之【简单计算器】
- SIP中OPTIONS方法的用法及示例
- json对象与字符串互转
- 教你50招提升ASP.NET性能(十):减少通过网络发送的数据
- php中的数组定义和使用
- 如何获得Windows 8中已记住的WIFI的明文密码
- 武汉科技大学ACM :1002: 零起点学算法28——判断是否闰年
- SQL Server 创建数据库快照
- app被Rejected 的各种原因翻译(转)
- localhost和127.0.0.1区别
- C++成员变量与函数内存分配
- linux、hdfs、hive、hbase经常使用的命令
- vue学习笔记(四)——Vue实例以及生命周期
- 小E浅谈丨区块链治理真的是一个设计问题吗?
- 关于vue的computed、filters、watch
- 安装FrameWork后重新注册IIS
- (转)Spring Boot 2 (七):Spring Boot 如何解决项目启动时初始化资源
- Lombok插件
热门文章
- lua、python对比学习
- IPSecVPN介绍 &; (Cisco Packet Tracer)IPSecVPN实验演示
- C++雾中风景15:聊聊让人抓狂的Name Mangling
- Electron安装过程深入解析(读完此文解决Electron应用无法启动,无法打包的问题)
- 不知如何创建UML电路图?看看本文
- Power Designer建模之餐饮在线点评系统——业务处理模型
- Prometheus第一篇:Prometheus架构解析
- CDH5部署三部曲之二:部署和设置
- S3C6410中断系统
- lumen-ioc容器测试 (5)