Blocking Queue BlockingQueue Actual Combat and Principle Analysis II

Table of contents

1. Introduction to SynchronousQueue

1.1 synchronousQueue combat

 1.2 Source code analysis (TODO)

2. Introduction to Priority Blocking Queue 

2.1 PriorityBlockingQueue combat

2.2 Source code analysis (TODO)

3. Introduction to LinkedTransferQueue

4. Introduction to DelayQueue 

4.1 Source code analysis

5. How to choose a suitable blocking queue 


1. Introduction to SynchronousQueue

synchronousQueue is a blocking queue without data buffering. It is applied in newCachedThreadPool. Its size is 0. Every time data fetching needs to block the thread, and storing data also needs to block the thread.

By default, the unfair lock is implemented using the stack structure at the bottom layer, and the fair lock is implemented using the queue structure.

The underlying locking uses the form of CAS + spin (512 times by default) + (park/unpark) to guarantee performance.

1.1 synchronousQueue combat

Two producers and two consumers: Last-in-first-out occurs. Conforms to the unfair lock feature, and the bottom layer is implemented using the stack structure.

import java.util.concurrent.SynchronousQueue;

public class SynchronousQueueTest {

    //定义一个synchronousQueue
    private final static SynchronousQueue synchronousQueue = new SynchronousQueue();

    public static void main(String[] args) throws Exception{

        //模拟消费者取数据
        new Thread(()->{
            try {
                synchronousQueue.take();
                System.out.println(Thread.currentThread().getName()+"取数据");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"consumer1").start();

        new Thread(()->{
            try {
                synchronousQueue.take();
                System.out.println(Thread.currentThread().getName()+"取数据");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"consumer2").start();

        //模拟生产者放数据
        new Thread(()->{
            try {
                synchronousQueue.put(1);
                System.out.println(Thread.currentThread().getName()+"生产数据");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"producer1").start();

        new Thread(()->{
            try {
                synchronousQueue.put(1);
                System.out.println(Thread.currentThread().getName()+"生产数据");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"producer2").start();
    }
}

 1.2 Source code analysis (TODO)

focus point:

1. Consumer enqueue blocking and CAS spin

2. The producer goes out of the queue and wakes up

3. put and take methods

2.  Introduction to Priority Blocking Queue 

PriorityBlockingQueue is an unbounded array-based priority blocking queue. The default array length is 11, but it can be expanded wirelessly until the resources are exhausted.

The data will be sorted in ascending order after being stored.

The queue defaults to the highest priority first out.

Application Scenario: VIP Priority Purchase

How to design a priority queue?

PriorityBlockingQueue uses the idea of ​​big top heap and small top heap, big top heap: the value of the parent element is always greater than that of the child element. Small top heap: The value of the parent element is always smaller than the child element.

2.1  PriorityBlockingQueue combat

PriorityBlockingQueue gets data and sorts the stored data

import java.util.Random;
import java.util.concurrent.PriorityBlockingQueue;

public class PriorityBlockingQueueTest {

    //定义一个初始容量为3的队列,队列会自动扩容
    private static PriorityBlockingQueue priorityBlockingQueue = new PriorityBlockingQueue(3);
    public static void main(String[] args) throws InterruptedException {

        //存5个数据
        System.out.println("存数据");
        for(int i=0;i<5;i++){
            Random random = new Random();
            int j = random.nextInt(100);
            System.out.print(j+" ");
            priorityBlockingQueue.put(j);
        }

        //取5个数据
        System.out.println("");
        System.out.println("取数据");
        for(int i=0;i<5;i++){
            System.out.print(priorityBlockingQueue.take()+" ");
        }

    }
}

2.2 Source code analysis (TODO)

 focus point:

1. Modified constants: maximum number, reentrant lock, condition queue condition

2. put and take methods (the code of the small top heap)

3. Introduction to LinkedTransferQueue

 LinkedTransferQueue is an unbounded blocking queue implemented by a linked list. Use CAS+spin method to lock. It is a combination of synchronousQueue and linkedBlockingQueue, both of which can be implemented.

The put method does not block.

The transfer will block, judge the blocking method, and see if the method throws an interrupt exception. 

4. Introduction to DelayQueue 

DelayQueue is an unbounded blocking queue implemented by a priority queue, which can achieve the effect of delayed closing.

Application scenarios: order timeout closing, asynchronous SMS notification, closing idle connections, caching, task timeout, etc.

lock: reentrantLock guaranteed

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

public class DelayQueueTest {

    public static void main(String[] args) throws InterruptedException {
        //定义一个delayQueue
        BlockingQueue<DelayedObject> delayeds = new DelayQueue<>();
        delayeds.put(new DelayedObject("A",1000 * 10));
        delayeds.put(new DelayedObject("B",4000 * 10));
        delayeds.put(new DelayedObject("C",3000 * 10));
        delayeds.put(new DelayedObject("D",2000 * 10));

        //取出元素
        System.out.println(delayeds.take());
        System.out.println(delayeds.take());
        System.out.println(delayeds.take());
        System.out.println(delayeds.take());

    }
}

class DelayedObject implements Delayed{

    private String name;
    private long delayTime;

    public DelayedObject(String name,long delayTime) {
        this.name = name;
        this.delayTime =  System.currentTimeMillis() + delayTime;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return 0;
    }

    @Override
    public int compareTo(Delayed o) {
        return 0;
    }

    @Override
    public String toString() {
        Date date = new Date(delayTime);
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        return "\nDelayObject:{"
                + "name=" + name
                + ", time=" + sd.format(date)
                + "}";
    }

}

4.1 Source code analysis

1. put and take methods

5. How to choose a suitable blocking queue 

Five indicators:

1. Function

2. Capacity: Fixed capacity ( ArrayBlockingQueue ) unlimited capacity ( LinkedBlockingQueue ) no capacity ( SynchronousQueueDelayQueue capacity (Integer.MAX_VALUE)

3. Can it be expanded?

        No need to expand ( ArrayBlockingQueue ) Need to expand ( PriorityBlockingQueue )

4. Memory structure

        Array ( ArrayBlockingQueue ) linked list ( LinkedBlockingQueue )

5. Performance

        LinkedBlockingQueue (two locks)

        ArrayBlockingQueue (a lock)

        SynchronousQueue (direct delivery)

Guess you like

Origin blog.csdn.net/qq_21575929/article/details/124807322