java 伪异步 netty,大话netty系列之--伪异步BIO

生意规模扩大

话说,老王和大明的生意越来越好,这就需要两个人增强业务往来,由于天南地北,两个人只能每次运输都需要雇一个人去运货(new 一个线程),一个月下来,两人一算,人力成本太大了,光是雇佣人一个月就用了将近一百个人,本来生意旺盛,却还亏损了。两个人思来想去,想到了一个好主意,可以租个宿舍,就固定雇佣几个人,谁闲着谁就去运输,这样可以大大降低人的数量,又可以充分发挥人的效率。

其实上面这种思路就是服务端每次新连接客户端不在new一个线程,二是创建一个线程池,这样避免线程的大量创建,下面我们来用代码实现下以上的逻辑。

首先创建老王类,和昨天的BIO没有什么区别:

/**

* 伪异步请求 老王

*

* @author wangmj

* @since 2018/11/19

*/

public class FakeBioClient {

public static void main(String[] args) {

int port = 8761;

Socket socket = null;

PrintWriter out = null;

BufferedReader in = null;

try {

//创建客户端soket--老王

socket = new Socket("127.0.0.1", port);

while (true) {

//获取输出流,向服务器发送消息

OutputStream os = socket.getOutputStream();

out = new PrintWriter(os, true);

out.println("今天给你发送东北特产100斤,发送时间:" + new Date());

System.out.println("老王的东北特产成功送出");

in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

//收到服务端的响应

String resp = in.readLine();

System.out.println("收到大明的反馈=" + resp);

Thread.sleep(500);

}

} catch (IOException e) {

e.printStackTrace();

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

if (out != null) {

out.close();

}

try {

if (in != null) {

in.close();

}

if (socket != null) {

socket.close();

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

接着我们创建工人管理宿舍—线程池

/**

* @author wangmj

* @since 2018/11/19

*/

public class FakeBioServerExecutePool {

private ExecutorService executor;

public FakeBioServerExecutePool() {

executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), 100, 120L, TimeUnit.SECONDS, new ArrayBlockingQueue(5000));

}

public void execute(Runnable task) {

executor.execute(task);

}

}

有一点需要提醒,创建线程池不要用Excecutors类创建,尽量用new ThreadPoolExecutor创建,因为这样可以自己定义线程池参数,并且可以自己定义拒绝策略。

现在我们继续创建小美类,大明的具体业务处理对象:

/**

* @author wangmj

* @since 2018/11/19

*/

public class FakeBioServerHandler implements Runnable {

private Socket socket;

public FakeBioServerHandler(Socket socket) {

this.socket = socket;

}

public void run() {

BufferedReader in = null;

PrintWriter out = null;

try {

in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

out = new PrintWriter(socket.getOutputStream(), true);

//从大明收到的特产

String messageFromDM = null;

while (true) {

messageFromDM = in.readLine();

if (messageFromDM == null) {

break;

}

System.out.println("收到老王的特产=" + messageFromDM);

out.println("老铁,已收到特产,接收时间:" + new Date());

System.out.println("通知老王已收到特产");

}

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

if (in != null) {

in.close();

}

} catch (IOException e) {

e.printStackTrace();

}

if (out != null) {

out.close();

}

}

}

}

最后我们创建大明类:

/**

* 大明类,负责接收老王发过来的特产

*

* @author wangmj

* @since 2018/11/19

*/

public class FakeBioServer {

public static void main(String[] args) {

int port = 8761;

Socket socket = null;

try {

//创建大明类

ServerSocket serverSocket = new ServerSocket(port);

socket = serverSocket.accept();

System.out.println("创建大明类成功,并阻塞等待老王发送的特产");

FakeBioServerExecutePool executePool = new FakeBioServerExecutePool();

executePool.execute(new FakeBioServerHandler(socket));

} catch (IOException e) {

e.printStackTrace();

}

}

}

好,这样一条龙我们就都创建完毕,包括了客户端,服务端及服务端的线程池,让我们运行下查看结果,

客户端运行结果—老王类

c5c8d6d5e623094e5ae60c1e94235e0d.png

服务端运行结果–大明类

62f8642e0823a355764b069b20484ff6.png

原理分析

首先,这次创建的客户端及服务端还是基于BIO,也就是说读写还是会同步阻塞,只不过这次我们将服务端每次接收新的连接不是每次都new Thread创建线程,而是用线程池来管理线程,想以此来减少线程的创建,并且设定了一个最大任务队列;模型图如下(模型图用的processon画的,画的不怎么好)

91dd919925fc2e8af88e6dd2bc5a1249.png

分析:

当任务足够多,并且网络较差,造成一次IO的时间过多,就会造成队列堆积大量等待任务,由于服务端只有一个acceptor处理,新的客户端连接就会被拒绝,那么最终会导致队列中堆积大量的请求,同时客户端连接失败,服务端CPU飙升,系统崩溃,所以伪异步IO模型解决不了问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值