Java并发编程的艺术:(6)Java 并发容器和框架之 ConcurrentLinkedQueue
在并发编程中,有时候需要使用线程安全的队列。如果要实现一个线程安全的队列有两种方式:一种是使用阻塞算法,另一种是使用非阻塞算法。使用阻塞算法的队列可以用一个锁(入队和出队用同一把锁)或两个锁(入队和出队使用不同的锁)等方式来实现。非阻塞的实现方式则可以使用循环 CAS 的方式来实现。
ConcurrentLinkedQueue 是一个机遇链接节点的*线程安全队列,它采用先进先出的规则对节点进行排序,当我们添加一个元素的时候,他会添加到队列的尾部;当我们获取一个元素时,它会返回队列头部的元素。它采用了 “wait-free” 算法(CAS)来实现,该算法在 Michael & Scott 算法基础上进行了一些修改。
ConcurrentLinkedQueue 的结构
ConcurrentLinkedQueue 由 head 节点和 tail 节点组成,每个节点(Node)由节点元素(item)和指向下一个节点(next)的引用组成,节点之间就是通过这个 next 关联起来,从而组成一张链表结构的队列。默认情况下 head 节点存储的元素为空, tail 节点等于 head 节点。
private transient volatile Node<E> tail = head;
入队列
入队列就是将入队节点添加到队列的尾部。插入的过程就是数据结构中学习的队列的操作,不过这里边在 tail 节点插入时采用了 CAS 算法保证线程安全。
出队列
出队列首先获取头节点的元素,然后判断头节点元素是否为空,如果为空,表示另外一个线程已经进行了一次出队操作将该节点的元素去走,如果不为空,则使用 CAS 的方法将头节点的引用设置为 null,如果 CAS 成功,则直接返回头节点的元素,如果不成功,表示另外一个线程已经进行了一次出队操作更新了 head 节点,导致元素发生了变化,需要重新获取头节点。
学过数据结构之后,这部分内容非常容易理解,ConcurrentLinkedQueue 跟普通的队列区别在于,为了保证并发下的线程安全,对队列的修改操作采用了 CAS 算法,仅此而已。
参考
《Java 并发编程的艺术》
上一篇: Java并发编程的艺术
下一篇: IIS如何设置只允许访问某些文件