当服务器收到客户端 X 的请求后(读取到所有请求数据后),将这个请求送入一个独立线程进行处理,然后主线程继续接收客户端 Y 的请求。
客户端一侧也可以使用一个子线程和服务器端进行通信。这样客户端主线程的其他工作就不受影响了,当服务器端有响应信息时再由这个子线程通过监听模式/观察模式或者类似的其他设计模式通知主线程。

服务端

package testBlockSocket;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; // 通过多线程的方式处理socket的连接
public class SocketServer2MiltiThread {
private final static Logger LOGGER = LoggerFactory.getLogger(SocketServer2MiltiThread.class); public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8888);
try {
while (true) {
Socket socket = serverSocket.accept();
// 业务处理过程可以交给一个线程,不过线程的创建很耗资源
// 最终改变不了, accept () 只能在被阻塞的情况一个一个接收 Socket
SocketServerThread socketServerThread = new SocketServerThread(socket);
Thread thread = new Thread(socketServerThread);
thread.start();
}
} catch (Exception e) {
SocketServer2MiltiThread.LOGGER.error(e.getMessage(), e);
} finally {
if (serverSocket != null) {
serverSocket.close();
// 当然 , 接收到客户端的 Socket 后 , 业务的处理过程可以交给一个线程来做
}
}
} } class SocketServerThread implements Runnable {
private final static Logger LOGGER = LoggerFactory.getLogger(SocketServerThread.class); private Socket socket; public SocketServerThread(Socket socket) {
this.socket = socket;
} @Override
public void run() {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
// 下面我们收取信息
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
Integer sourcePort = socket.getPort();
int maxLen = 1024;
byte[] contextBytes = new byte[maxLen];
// 同样无法改变 read 方法被阻塞,直到操作系统有数据准备好的现象
int realLen = inputStream.read(contextBytes, 0, maxLen);
String message = new String(contextBytes, 0, realLen);
LOGGER.info("服务器收到来自于端曰 :" + sourcePort + " 的信息:" + message);
// 下面开始发送响应信息
outputStream.write("因发响应信息 !".getBytes());
} catch (Exception e) {
SocketServerThread.LOGGER.error(e.getMessage(), e);
} finally {
// 试图关闭连接
try {
inputStream.close();
outputStream.close();
socket.close();
} catch (Exception e) {
SocketServerThread.LOGGER.error(e.getMessage(), e);
}
}
} }

1)虽然在服务器端,接收到数据后的处理交给了 一个独立线程进行,但是操作系 统通知accept()的方式还是单个线程运行的 。 也就是说,实际上是服务器接收到数据报文后的“业务处理过程”可以应用多线程技术,但是数据报文的接收还是需要一个接一个地来,从以上的示例代码和其调试过程我们都可以明确看到这一点。
          2)在 Linux 系统中,可以创建的线程是有限的。可以通过 cat /proc/sys/kernel/threads-max命令查看可以创建的最大线程数。当然这个值可以更改,但是参与调度的线程数量越大, CPU 用在线程间切换所需的时间也就越长,用来处理真正业务的资源也就越少。CPU 线程状态间切换的性能消耗是非常巨大的,后文我们会对这个描述给出相应的实例以便将这个感性的认识具体化,帮助读者真正认识线程间状态切换的性能代价 。
         3)创建一个线程是有较大的资源消耗的 。 例如 NM 创建一个线程时,即使这个线程不做任何工作,JVM都会分配一个独立线程技空间(不同 JDK 版本默认的大小不一样〉 。虽然它可以通过“-Xss ”参数进行大小调整,但这不影响 CPU 一级、 二次缓存中的数据出现线程数据的换入/换出 。

总结:

阻塞模型的问题关键不在于是否使用了多线程(包括线程池)处理并发请求,而在于 accept()、 read()的操作点都被阻塞了 。

网络I/O模型--02阻塞模式(多线程)的更多相关文章

  1. 网络I/O模型--01阻塞模式(普通)

    很长一段时间内,大多数网络通信方式都是阻塞模式,即: · 客户端 向服务器端发出请求后,客户端会一直处于等待状态(不会再做其他事情),直到服务器端返回结果或者网络出现问题 . · 服务器端同样如此,当 ...

  2. Socket 阻塞模式和非阻塞模式

    阻塞I/O模型: 简介:进程会一直阻塞,直到数据拷贝 完成 应用程序调用一个IO函数,导致应用程序阻塞,等待数据准备好. 如果数据没有准备好,一直等待….数据准备好了,从内核拷贝到用户空间,IO函数返 ...

  3. 网络IO模型与Reactor模式

    一.三种网络IO模型: 分类: BIO 同步的.阻塞式 IO NIO 同步的.非阻塞式 IO AIO 异步非阻塞式 IO 阻塞和同步的概念: 阻塞:若读写未完成,调用读写的线程一直等待 非阻塞:若读写 ...

  4. 简明网络I/O模型---同步异步阻塞非阻塞之惑

    转自:http://www.jianshu.com/p/55eb83d60ab1 网络I/O模型 人多了,就会有问题.web刚出现的时候,光顾的人很少.近年来网络应用规模逐渐扩大,应用的架构也需要随之 ...

  5. 网络I/O模型---同步异步阻塞非阻塞之惑

    网络I/O模型 人多了,就会有问题.web刚出现的时候,光顾的人很少.近年来网络应用规模逐渐扩大,应用的架构也需要随之改变.C10k的问题,让工程师们需要思考服务的性能与应用的并发能力. 网络应用需要 ...

  6. UNIX网络编程读书笔记:I/O模型(阻塞、非阻塞、I/O复用、信号驱动、异步)

    I/O模型 UNIX下可用的5种I/O模型: (1)阻塞I/O (2)非阻塞I/O (3)I/O复用(select和poll) (4)信号驱动I/O(SIGIO) (5)异步I/O 对于一个套接口上的 ...

  7. 网络IO模型 非阻塞IO模型

    网络IO模型 非阻塞IO模型 同步 一件事做完后再做另一件事情 异步 同时做多件事情 相对论 多线程 多进程 协程 异步的程序 宏观角度:异步 并发聊天 阻塞IO 阻塞IO的问题 一旦阻塞就不能做其他 ...

  8. TCP同步与异步及阻塞模式,多线程+阻塞模式,非阻塞模式简单介绍

    首先我简单介绍一下同步TCP编程 与异步TCP编程. 在服务端我们通常用一个TcpListener来监听一个IP和端口.客户端来一个请求的连接,在服务端可以用同步的方式来接收,也可以用异步的方式去接收 ...

  9. 转:PHP中实现非阻塞模式

    原文来自于:http://blog.csdn.net/linvo/article/details/5466046 程序非阻塞模式,这里也可以理解成并发.而并发又暂且可以分为网络请求并发 和本地并发 . ...

随机推荐

  1. php 中的查找算法 和 排序方法(多字段排序)

    一.查找算法 1.顺序查找(一个一个查,效率低,不用多说) 2.二分查找 /* php 二分查找 在$a数组里查找$x的位置 $a必须是一个以升序排序后的数组 */ function binsearc ...

  2. C#数据库连接方法

    一:C# 连接SQL数据库 Data Source=myServerAddress;Initial Catalog=myDataBase;User Id=myUsername;Password=myP ...

  3. 6.关于Xamarin Android对APK包大小的处理

    降低学习成本是每个.NET传教士义务与责任. 建立生态,保护生态,见者有份. 对于apk 包的大小大家都是很敏感的,虽然现在安卓手机的性能和存储越来越厉害了.本着能少一点是一点的态度,我们还是要深入理 ...

  4. (转)AIX的Dump文件学习笔记

    原文:http://czmmiao.iteye.com/blog/1144999 DUMP文件概述 为了增强故障分析能力,IBM的服务器增加了对设备故障当前环境的保存功能,就是保存一份设备故障时的内存 ...

  5. HttpURLConnection解析

    请求响应流程 设置连接参数的方法 setAllowUserInteraction setDoInput setDoOutput setIfModifiedSince setUseCaches setD ...

  6. Spring中的BeanPostProcessor

    一.何谓BeanProcessor BeanPostProcessor是SpringFramework里非常重要的核心接口之一,我先贴出一段源代码: /* * Copyright 2002-2015 ...

  7. 删除Open with Atom右键菜单

    特别特别讨厌Atom的右键菜单,叕没有设置项可以去掉,烦!安装完RegScanner v2.15汉化版之后,开始搜索删除Atom的右键菜单 1.打开E:\RegScanner2.加载配置文件 E:\R ...

  8. Android 开发工具类 12_PullXmlTools

    xml 格式数据 <?xml version="1.0" encoding="UTF-8"?> <user-list> <user ...

  9. 原生js动态添加style,添加样式

    原生js动态添加style,添加样式 第一种 var style="[assign-url='"+str+"']{display:initial}"; var ...

  10. OpenStack-Queens版 实践

    OpenStack简介 OpenStack是一个由NASA(美国国家航空航天局)和Rackspace合作研发并发起的,以Apache许可证授权的自由软件和开放源代码项目. OpenStack是一个开源 ...