首页 > 编程知识 正文

多线程读redis队列,java线程锁有几种

时间:2023-05-06 21:04:12 阅读:133419 作者:133

在前链的种类和分析中提到了自旋链中的CLH和MCS,特转载此篇对CLH有详细的了解。

原文地址: JAVA同时编程学习笔记的CLH队列锁

NUMA与SMP

系统多处理器(SMP ),即多处理器配置,服务器中的多个CPU是对称的,并且每个CPU访问存储器地址所需的时间相同。 主要特征是共享,包括共享CPU、存储器、I/O等。 SMP的优点是可以确保内存一致性。 缺点是这些共享资源很可能成为性能瓶颈。 随着CPU数量的增加,每个CPU都会访问同一内存资源,这可能会导致内存访问冲突,从而导致CPU资源的浪费。 常用的电脑就属于这一类。

非统一存储器访问(numa )不一致的存储访问将CPU划分为CPU模块,每个CPU模块由多个CPU组成,并具有独立的本地存储器、I/O插槽等模块之间可以通过互连模块相互访问,本地内存访问速度远远快于远程内存(系统中其他节点的内存)。NUMA的优点是可以很好地解决原始SMP系统的扩展问题缺点是,由于对远程存储器的访问延迟远远超过本地存储器,所以随着CPU的数量的增加,系统的性能不会线性地增加。

CLH算法实现

CLH队列中的节点QNode包含锁定字段。 如果此字段为true,则表示线程必须获得锁定,且不会解除锁定;如果为false,则表示线程已解除锁定。 节点之间用看不见的链表连接。 之所以称为不可见的链表,是因为这些节点之间没有明显的next指针,myPred指向的节点变化会影响myNode的行为。 CLHLock还有一个末端指针,它始终指向队列中的最后一个节点。 CLHLock的类图如下:

如果线程需要获取锁定,则会创建新的QNode。 如果其中的locked设置为true,则表示需要获取锁定。 然后,线程对tail域调用getAndSet方法以在队列末尾获取对上一个节点的引用myPred,该线程在上一个节点的locked字段中旋转直到解锁。 如果线程需要解除锁定,请将当前节点的locked域设置为false,以重用前向节点。 如下图所示,线程a需要获取锁定。 myNode域为true,tail指向线程a的节点,线程b也添加在线程a之后,tail指向线程b的节点。 接着,线程a和b在其myPred域上旋转,并且当其myPred节点的locked字段变为false时,可以获得锁定扫描行。 很明显,线程a的myPred locked域为false,此时线程a获得了锁定。

整个CLH的代码如下所示。 其中,使用ThreadLocal类,将QNode绑定到每个线程,同时使用AtomicReference。 对尾指针的更改是通过调用它的getAndSet ) )操作实现的,以确保对象引用以原子方式更新。

publicclassclhlockimplementslock { atomicreferenceqnodetail=newatomicreferenceqnode (new qnode ); ThreadLocalQNode myPred; ThreadLocalQNode myNode; publicclhlock ((tail=newatomicreferenceqnode ) ); myNode=new ThreadLocalQNode () { protected QNode initialValue ) { return new QNode ); }; myPred=new ThreadLocalQNode () { protected QNode initialValue ) { return null; }; } @Override public void lock () { QNode qnode=myNode.get ); qnode.locked=true; qnodepred=tail.getandset(qnode ); mypred.set(pred; while(pred.locked ) { } } @Override public void unlock () { QNode qnode=myNode.get ); qnode.locked=false; mynode.set(mypred.get ) ); }从代码中可以看到,lock方法具有while循环。 这是一个等待的过程,其中在等待之前指向节点的锁定域为false,并等待自旋。 unlock方法很简单,只需将自己的锁定域设置为false即可。

CLH优缺点

CLH队列锁定的优点是空间复杂度低。 (如果有n个线程,l个锁,并且每个线程一次只能获取一个锁,则所需的存储空间为o(ln ),n个线程有n个myNode,l个锁有l个tail ),CLH的变体唯一的缺点是在NUMA系统结构中性能较差。 在这种系统结构中,每个线程都有自己的存储器,并且如果前向节点的存储器位置较远,则自旋确定前向节点的锁定域将导致性能严重下降,但在SMP系统结构中该方法非常有效。 解决NUMA系统结构的一种思路是MCS队列锁。

原文地址: JAVA同时编程学习笔记的CLH队列锁

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。