阻塞模式

来源:互联网 发布:淘宝互刷平台686 编辑:程序博客网 时间:2024/05/22 09:59

阻塞模式

客户端向服务器发出请求后,客户端会一直处于等待状态(不会再做其他事情),直到服务器端返回结果或者网络出现问题。
服务器端同样如此,当在处理某个客户端A发来的请求时,另一个客户端B发来的请求会等待,直到服务器端的处理线程完成上一个请求的处理。
Java对阻塞模式的支持,就是由java.net包中的Socket套接字功能完成的。Socket套接字是TCP/UDP等传输层协议在高级编程语言中的具体体现。例如客户端使用TCP协议连接这台服务器的时候,当TCP三次握手成功后,应用程序就会创建一个Socket套接字对象(注意,这时还没有进行数据内容的传输),当这个TCP链接出现数据传输时,Socket套接字就会把数据传输的表现告诉程序员。
传统的阻塞模型在通信方式上存在几个问题:
1、同一时间,服务器只能接收来自于客户端A的请求信息;虽然客户端A个客户端B的请求是同时进行的,但客户端B发送的请求信息也只能等到服务器接收完客户端A的请求数据后,才能被接收。
2、由于服务器一次只能处理一个客户端请求,当处理完成并返回后(或者异常时),才能进行第二次请求的处理。很显然,这样的处理方式在高并发的情况下,是不建议采用的。

当尝试使用多线程技术来解决这个问题时的方法:
当服务器收到客户端X的请求后(读取到所有请求数据后),将这个请求送入一个独立线程进行处理,然后主线程继续接收客户端Y的请求。
客户端一侧也可以使用一个子线程和服务器进行通信。这样客户端主线程的其他工作就不受影响了,当服务器端有响应信息时再由这个子线程通过监听模式/观察模式或者类似的其他方式模式通知主线程。
但是使用多线程来解决这个问题实际上是有局限性的:
虽然在服务器端,接收到数据后的处理交给了一个独立线程进行,但是操作系统通知accept()的方式还是单个线程运行的。也就是说,实际上是服务器接收到数据报文后的“业务处理过程”可以应用多线程技术,但是数据报文的接收还是需要一个接一个地来。
在Linux系统中,可以创建的线程是有限的。可以通过cat/proc/sys/kernel/threads-max命令查看可以创建的最大线程数。当然这个值可以修改,但是参与调度的线程数量越大,CPU用在线程间切换所需的时间也就越长,用来处理真正业务的资源也就越少。CPU线程状态间切换的性能消耗死非常巨大的。
创建一个线程是有较大的性能消耗的。例如JVM创建一个线程时,即使这个线程不做任何工作,JVM都会分配一个独立线程空间(不同JDK版本默认的大小不一样)。虽然它可以通过“-Xss”参数进行大小调整,但这不影响CPU一级、二次缓存中的数据出现线程数据的换入/换出。
当然,还可以使用类似Java语言中ThreadPoolExecutor这样的线程池来缓解线程创建和切换的资源消耗问题,但是又会造成线程池中待处理任务的持续增加,同样消耗了大量内存资源。另外,如果应用程序中还大量使用长连接,那么线程池中的线程就会被对应的任务持续占用,这样一来系统资源的消耗更容易失控。
原创粉丝点击