当前位置:网站首页>How to use concurrentlinkedqueue as a cache queue

How to use concurrentlinkedqueue as a cache queue

2022-07-04 21:33:00 Xiaoqu classmate

In the project , We may use queues , that ConcurrentLinkedQueue, Is an essential . For multithreaded environments , Want to achieve thread safety , Or lock it yourself , Or use thread safe queues -------ConcurrentLinkedQueue.

Let's see how to use it ConcurrentLinkedQueue How to build a cache queue .

package server.utils;

import java.util.concurrent.ConcurrentLinkedQueue;

public class QueueUtils {
    

    // User cache queue 
    private static final ConcurrentLinkedQueue<String> queueCache = new ConcurrentLinkedQueue<>();


    private int rank;

    // The team 
    public void offer(String userId) {
    
        queueCache.offer(userId);
    }

    // Determine whether an element exists 
    public boolean isExist(String userId) {
    
        if (queueCache.contains(userId)) {
    
            return true;
        }
        return false;
    }

    // Get ranking 
    public int getRank(String userId) {
    
        if (isExist(userId)) {
    
            for (String id : queueCache) {
    
                if (id.equals(userId)) {
    
                    break;
                }
                rank++;
            }
            System.out.printf("rank Ranked as " + rank);
            return rank;
        } else {
    
            // If not, join the end of the team 
            offer(userId);
            rank = queueCache.size() + 1;
            System.out.printf(" If users are not included, join the end of the team " + rank);
            return rank;
        }
    }

    public static void main(String[] args) {
    
        for (int i = 1; i < 6; i++) {
    
            new QueueUtils().getRank("1" + i);
        }
        new QueueUtils().getRank("15");
    }
}

 Insert picture description here

Summarize the three common methods :peak(),poll() Method ,offer() Method

peak() Method :

The function of this method is to get the elements of the queue header , Get only, don't remove , Pay attention to this method and the following poll The difference between methods !

public E peek() {
    
    //[1]goto sign 
    restartFromHead:
    for (;;) {
    
        for (Node<E> h = head, p = h, q;;) {
    
            //[2]
            E item = p.item;
            //[3]
            if (item != null || (q = p.next) == null) {
    
                updateHead(h, p);
                return item;
            }
            //[4]
            else if (p == q)
                continue restartFromHead;
            else//[5]
                p = q;
        }
    }
}
   final void updateHead(Node<E> h, Node<E> p) {
        
           if (h != p && casHead(h, p))  {
       
             h.lazySetNext(h); 
       }

poll() Method :

This method is to get the node of the header , Return if the queue is empty null;

public E poll() {
    
    // This is actually a goto The tag , For jumping out for loop 
    restartFromHead:
    //[1]
    for (;;) {
    
        for (Node<E> h = head, p = h, q;;) {
    
            E item = p.item;
            //[2] If the value stored in the current node is not empty , be CAS Set to null
            if (item != null && p.casItem(item, null)) {
    
                //[3]CAS Update the location of the header node after success 
                if (p != h) 
                    updateHead(h, ((q = p.next) != null) ? q : p);
                return item;
            }
            //[4] The current queue is empty , Just go back to null
            else if ((q = p.next) == null) {
    
                updateHead(h, p);
                return null;
            }
            //[5] The current node is the same as the next node , Description node self reference , Then find the head node again 
            else if (p == q)
                continue restartFromHead;
            //[6]
            else
                p = q;
        }
    }
}

final void updateHead(Node<E> h, Node<E> p) {
    
    if (h != p && casHead(h, p))
        h.lazySetNext(h);
}

offer() Method :

The function of this method is to add a node at the end of the queue , If the parameter passed is null, Throw a null pointer exception , Otherwise, because the queue is unbounded , This method will always return true, And this method uses CAS algorithmic , therefore Will not block threads ;

// Add a node at the end of the queue 
public boolean offer(E e) {
    
    // If e It's empty , Then throw a null pointer exception 
    checkNotNull(e);
    // Encapsulate the incoming elements into a node ,Node In the constructor UNSAFE.putObject(this, itemOffset, item) hold e Assigned to item
    final Node<E> newNode = new Node<E>(e);

    //[1]
    // there for The loop starts at the last node 
    for (Node<E> t = tail, p = t;;) {
    
      Node<E> q = p.next;
      //[2] If q by null, explain p It's the last node 
        if (q == null) {
    
            //[3]CAS to update : If p The next node of the node is null, Just update the write node to newNode
            if (p.casNext(null, newNode)) {
    
                //[4]CAS success , But at this moment p==t, So I won't enter here if Inside , Go straight back to true
                // So when will you come here ? In fact, another thread is also calling offer Method time , Will enter here 
                if (p != t) 
                    casTail(t, newNode);  
                return true;
            }
        }
        else if (p == q) //[5]
            
            p = (t != (t = tail)) ? t : head;
        else //[6]
            p = (p != t && t != (t = tail)) ? t : q;
    }
}

summary :

In fact, there are still several methods left unsaid , But I feel it's easier, so I don't waste space , You can have a look if you are interested :size Method is used to calculate the number of nodes in the queue , But because there is no lock , Inaccurate under concurrent conditions ;remove Method to delete a node , In fact, it is traversal and then use equals Methods to compare item It is not the same , Only if there are multiple qualified nodes, only the first one will be deleted , Then return true, Otherwise return to false;contains Method to determine whether the queue contains the specified item The node of , That's traversal , be prone to ;

The hardest part is offer Methods and poll Method ,offer The method is to add nodes at the end of the queue , and poll Is to get the header node , And delete the first real queue node ( Be careful , There are two kinds of nodes , One is sentinel node , One is the node that actually stores data ), I also simply said poll Methods and peek Differences in methods , The latter is just getting , Instead of deleting !

原网站

版权声明
本文为[Xiaoqu classmate]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/185/202207042034361758.html