今天有个问题,既然redis是单线程的,那么像BLPOP这种的阻塞命令不会一直占用着线程,其他命令无法执行吗?然而事实上是可以执行的。

这个文章通过redis的源码讲的很清楚了。我总结补充一下人家的东西。
https://www.jianshu.com/p/xsMzfn

BLPOP key1 [key2 ] timeout 移出并获取列表的第一个元素,
如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止

redis的线程模型,是接收客户端命令的线程时 I/O 多路复用的,再通过文件事件分配器单线程执行的。如下图,程序总是会将所有产生事件的套接字都入队到一个队列里面, 然后通过这个队列, 以有序(sequentially)、同步(synchronously)、每次一个套接字的方式向文件事件分派器传送套接字: 当上一个套接字产生的事件被处理完毕之后(该套接字为事件所关联的事件处理器执行完毕), I/O 多路复用程序才会继续向文件事件分派器传送下一个套接字

RedissonUtil会阻塞吗 redis list阻塞_redis

那实际上我们关心的BLPOP 命令的执行就是在文件事件分派器分派后是怎么执行的了。

对BLPOP命令的处理流程是这样的:

  1. redis先找到对应的key的list,如果list不为空则pop一个数据返回给客户端;
  2. 如果list为空,或者list不存在,就将该key添加到一个blockling_keys的字典中,value就是想订阅该key的client链表。此时对应的client的为block状态
  3. 当有PUSH 类型的命令进来的时候,先从blocking_keys中查找是否存在对应的key,如果存在就往ready_keys这个链表中添加该key;同时将value插入到对应的list中,并响应客户端。
  4. 每次处理完客户端命令后都会遍历ready_keys,并通过blocking_keys找到对应的client,依次将对应list的数据pop出来并响应对应的client;同时检查是否需要再次block。

整个阻塞执行过程相当于是分散开的,每次请求结束后都判断之前的阻塞列表是否满足执行条件,类似我们用轮询来实现长连接的功能。所以看似阻塞的命令对其他命令的执行时不会有影响的,它们依然是单线程的。

参考:https://www.jianshu.com/p/xsMzfn