专栏名称: Java专栏
一个Java、Python、数据库、中间件、业内资讯、面试、学习资源等干货的知识分享社区。
目录
相关文章推荐
51好读  ›  专栏  ›  Java专栏

面试时说Redis是单线程的,被喷惨了!

Java专栏  · 公众号  ·  · 2020-10-31 18:00

正文

注意 文末有最新 Java实战 项目 面试题

作者|莱乌


Redis是单线程的,这话搁以前,是横着走的,谁都知道的真理。现在不一样, Redis 变了。再说这句话,多少得有质疑的语气来跟你辩驳一番。意志不坚定的,可能就缴械投降,顺着别人走了。


到底是什么样的,各位看官请跟小莱一起往下看:


- 思维导图 -




Reactor模式


反应器模式,你可能不太认识,如果看过上篇文章的话应该会有点印象。涉及到 Redis 线程它是一个绕不过去的话题。


1、传统阻塞IO模型


在讲反应器模式前,这里有必要提一下传统 阻塞 IO模型的处理方式。


在传统 阻塞 I O 模型 中,由一个独立的 Acceptor 线程来监听客户端的连接,每当有客户端请求过来时,它就会为客户端分配一个新的线程来进行处理。当同时有多个请求过来,服务端对应的就会分配相应 数量 的线程。这就会导致CPU频繁切换,浪费资源。


有的连接请求过来不做任何事情,但服务端还会分配对应的线程,这样就会造成不必要的线程开销。这就好比你去餐厅吃饭,你拿着菜单看了半天发现真他娘的贵,然后你就走人了。这段时间等你点菜的服务员就相当于一个对应的线程,你要点菜可以看作一个连接请求。


同时,每次建立连接后,当线程调用读写方法时,线程会被阻塞,直到有数据可读可写, 在此期间线程不能做其它事情。还是上边餐厅吃饭的例子,你出去转了一圈发现还是这家性价比最高。回到这家餐厅又拿着菜单看了半天,服务员也在旁边等你点完菜为止。这个过程中服务员什么也不能做,只能这么干等着,这个过程相当于阻塞。



你看这样的方式,每来一个请求就要分配一个线程,并且还得阻塞地等线程处理完。有的请求还只是过来连接下,什么操作也不干,还得为它分配一个线程, 服务器资 源要求那得多高啊。遇到高并发场景,不敢想象。 对于连接数目比较小的的固定架构倒是可以考虑。


2、伪异步IO模型


你可能了解过一种通过线程池优化的解决方案,采用线程池和任务队列的方式。这种被称作伪异步IO模型。


当有客户端接入时,将客户端的请求封装成一个 task 投递到后端线程池中来处理。线程池维护一个消息队列和多个活跃线程,对消息队列中的任务进行处理。



这种解决方案,避免了为每个请求创建一个线程导致的线程资源耗尽问题。 但是底层仍然是同步阻塞模型。如果线程池内的所有线程都阻塞了,那么对于更多请求就无法响应了。因此这种模式会限制最大连接数, 并不能从根本上解决问题。


我们继续用上边的餐厅来举例,餐厅老板在经营了一段时间后,顾客多了起来,原本店里的5个服务员一对一服务的话根本对付不过来。于是老板采用5个人线程池 的方 。服务员服务完一个客人后立刻去服务另一个。


这时问题出现了,有的客人点菜特别慢,服务员就得等待很长时间,直到客人点完为止。如果5个客人都点的特别慢的话,这5个服务员就得一直等下去,就会导致其余的顾客没有人服务的状态。这就是我们上边所说的线程池所有线程都被阻塞的情况。


那么这种问题该如何解决呢?别急, Reactor 模式就要出场了。


3、Reactor设计模式


Reactor 模式的基本设计思想是基于I/O复用模型来实现的。


这里说下 I/O复用模型 和传统IO多线程阻塞不同,I/O复 用模型中多个连接共用一个阻塞对象,应用程序只需要在一个阻塞对象等待。 当某个连接有新的数据可以处理时,操作系统通知应用程序,线程从阻塞状态返回,开始进行业务处理。







请到「今天看啥」查看全文