1-1.线程阻塞

来源:互联网 发布:美容院调整型内衣 知乎 编辑:程序博客网 时间:2024/06/05 13:38
在高并发情况下容易出现请求丢失(实际是线程阻塞)的问题,原因就是接口或服务是单线程的,而且没有加其他机制。
请求丢失其实就是接口阻塞造成的,而阻塞一般由于单线程造成的。

更正:
目前主流web服务器(如tomcat)本身就被设计成多线程的,对每一个http请求服务器都会启动一个线程来处理,这就意味着我们的接口天然就是多线程的。服务器自身的配置就已经决定了能同时并发的线程数,所谓的线程阻塞其实指服务器的线程阻塞。如果我们的接口执行效率比较低,速度比较慢,用户的请求数超过服务器的最大线程数时,会使得超出的请求被阻塞。如果我们的接口执行效率比较高,当前线程很快执行完任务,立即去响应超出的请求,超出的请求会很快得到处理而不会被阻塞,从而提高了系统的吞吐量和QPS/TPS

解决这个问题有两种方法:

(1)使用多线程(线程池)。
每次接受一个请求都创建一个线程来处理,好处是并发性好,能及时处理,不会丢失请求;缺点是如果每次请求都创建新线程会造成资源消耗。
解决方法:使用线程池,配置好线程池参数,可以将资源消耗控制在一定范围。

(2)使用缓存或队列。
如果一定要用单线程方式处理请求,并且不造成阻塞,可以使用缓存或队列。
每次接受请求首先将入参放入缓存或队列,接下来在线程内部循环取缓存或队列直到空,每次取得参数后再进行处理。
这种方式也就是使用单线程实现多线程的方式。

第一种方法使用线程池来执行异步任务,可以在一定程度上提高接口执行效率,降低线程阻塞的风险;
第二种方法不能避免线程阻塞,反而加大了线程阻塞的风险。因为在循环内部并没有启动异步线程来处理,所有的任务都是在当前接口里完成的,甚至当先线程要循环处理队列中的所有请求,所以反而加大了线程阻塞的风险。
除非在循环内部启动异步线程来处理,但这没有必要,因为线程池本身就有任务队列来管理,在接口里再设置任务队列没有必要。
与其再花1ms来设置任务队列,不如直接把任务提交给线程池来处理,让线程池来管理任务。

所以,对于这种线程阻塞的问题,要么优化接口执行效率,要么使用线程池,没有其他太好的办法。
0 0