同步阻塞消息处理
假如有这样一个系统功能,客户端提交Event 至服务器,服务器接收到客户请求之后开辟线程 处理客户请求,经过比较复杂的业务计算后将结果返回 给客户端 |
---|
以上设计存在几个显著的缺陷,具体如下。 |
---|
·同步Event提交,客户端等待时间过长 (提交Event时长+接受Event创建thread时长+业务处理时长+返回结果时长)会陷入阻塞 ,导致二次提交Event耗时过长。 |
·由于客户端提交的Event数量不多,导致系统同时受理业务数量有限,也就是系统整体的吞吐量不高 。 |
·这种一个线程处理一个Event的方式,会导致出现频繁的创建开启与销毁 ,从而增加系统额外开销 。 |
·在业务达到峰值的时候,大量的业务处理线程阻塞会导致频繁的CPU上下文切换 ,从而降低系统性能 。 |
异步非阻塞消息处理
前面分析了同步阻塞消息的处理方式存在诸多缺陷,尤其是系统的吞吐量低 ,很难应对比较高的业务并发量 。如果我们将同步阻塞的方式换成异步非阻塞的方式,则不仅可以提高系统的吞吐量 ,而且业务处理线程的数量也能够控制在一个固定的范围,以增加系统的稳定性 。 |
---|
客户端提交Event后会得到一个相应的工单并且立即返回 ,Event则会被放置在Event队列 中。服务端有若干个工作线程,不断地从Event队列中获取任务 并且进行异步处理 ,最后将处理结果保存至另外一个结果集 中,如果客户端想要获得处理结果,则可凭借工单号再次查询 。 |
---|
两种方式相比较,你会发现异步非阻塞的优势非常明显 |
---|
首先客户端不用等到结果处理结束之后才能返回,从而提高了系统的吞吐量 和并发量 ; |
其次若服务端的线程数量在一个可控的范围 之内是不会导致太多的CPU上下文切换从而带来的额外开销 的; |
再次服务端线程可以重复利用 ,这样就减少了不断创建线程带来的资源浪费 。 |
|
但是异步处理的方式同样也存在缺陷,比如客户端想要得到结果还需要再次 调用接口方法进行查询 (可以利用异步回调接口的方式来解决这个问题) |
服务端有若干个线程会从队列中获取相应的Event进行异步处理,那么这些线程又是如何从队列中获取数据的呢?换句话说就是如何知道队列里此时是否有数据呢? |
---|
比较笨的办法是不断地轮询 :如果有数据则读取数据并处理,如果没有则等待若干时间再次轮询。 |
还有一种比较好的方式就是通知 机制:如果队列中有Event,则通知工作的线程开始工作;没有Event,则工作线程休息并等待通知。 |
-----------------------------------------------------------------------------读书笔记摘自书名:Java高并发编程详解:多线程与架构设计 作者:汪文君