Blocking queue in java

Keywords: Java Back-end

preface

In the field of multithreading, the so-called blocking will suspend the thread (i.e. blocking) in some cases. Once the conditions are met, the suspended thread will wake up automatically.
Why do I need to block the queue?
The advantage is that we don't need to care about when to block the thread and what to wake up the thread, because all the blocking queues are done by ourselves. Before the concurrent package is released, in a multithreaded environment, each programmer must control these details by himself, especially taking into account efficiency and thread safety, which brings great complexity to our program.

Tip: the following is the main content of this article. The following cases can be used for reference

1, Type of blocking queue


BlockingQueue is the top-level interface of blocking queue. There are several blocking queues below:

ArrayBlockingQueue: a bounded blocking queue composed of an array structure.
LinkedBlockingQueue: a bounded (but the default size is Integer.MAX_VALUE) blocking queue composed of a linked list structure.
PriorityBlockingQueue: an unbounded blocking queue that supports prioritization.
DelayQueue: delay unbounded blocking queue implemented using priority queue.
Synchronous queue: a blocking queue that does not store elements, that is, a queue of individual elements.
LinkedTransferQueue: an unbounded blocking queue composed of a linked list structure.
LinkedBlockingDeque: a bidirectional blocking queue composed of linked lists.

Example: pandas is a NumPy based tool created to solve data analysis tasks.

Let's first look at the code that throws an exception:

public class BlockQueueDemo {
    public static void main(String[] args) {
        // Create a blocking queue. 3 is the capacity of the blocking queue
        BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);

        System.out.println(blockingQueue.add("a")); // true
        System.out.println(blockingQueue.add("b")); // true
        System.out.println(blockingQueue.add("c")); // true

        // Error Queue full when opening this line
        // System.out.println(blockingQueue.add("x")); //  The queue is full and cannot be added

        // Check whether there are elements in the blocking queue. If yes, take out the first element a, and if not, report an error NoSuchElementException
        System.out.println(blockingQueue.element()); // a 

        System.out.println(blockingQueue.remove()); // a
        System.out.println(blockingQueue.remove()); // b
        System.out.println(blockingQueue.remove()); // c

        // An error NoSuchElementException is reported when opening this line
//        System.out.println(blockingQueue.remove()); //  There are no more elements. You can't remove them
    }
}

Look at the code of the special value:

public class BlockQueueDemo {
    public static void main(String[] args) {
        // Create a blocking queue. 3 is the capacity of the blocking queue
        BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);

        System.out.println(blockingQueue.offer("a")); // true
        System.out.println(blockingQueue.offer("b")); // true
        System.out.println(blockingQueue.offer("c")); // true

        // Opening this line will not report an error Queue full like the add method
         System.out.println(blockingQueue.offer("x")); // false

        // Check whether there is an element in the blocking queue. If there is, take out the first element a. if there is no, an error is reported and null is returned
        System.out.println(blockingQueue.peek()); // a

        System.out.println(blockingQueue.poll()); // a
        System.out.println(blockingQueue.poll()); // b
        System.out.println(blockingQueue.poll()); // c

        // Open this row 
        System.out.println(blockingQueue.poll()); // null
    }
}

Blocking means that when the queue is full and the producer thread is putting, the queue will block the production thread until the put data or response interrupt exits. When the queue is empty and the consumer thread is taking, the queue will block the consumer thread until the queue is available.

public class BlockQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        // Create a blocking queue. 3 is the capacity of the blocking queue
        BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);

        blockingQueue.put("a");
        blockingQueue.put("b");
        blockingQueue.put("c");
        // Return false
//        blockingQueue.put("x");
        blockingQueue.take();
        blockingQueue.take();
        blockingQueue.take();

        // Return null
//        blockingQueue.take();

    }

Timeout:

public class BlockQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        // Create a blocking queue. 3 is the capacity of the blocking queue
        BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);

		// Indicates that the value in the queue will expire and be removed after 2 seconds
        System.out.println(blockingQueue.offer("a", 2, TimeUnit.SECONDS)); // true
        System.out.println(blockingQueue.offer("a", 2, TimeUnit.SECONDS)); // true
        System.out.println(blockingQueue.offer("a", 2, TimeUnit.SECONDS)); // true
        System.out.println(blockingQueue.offer("a", 2, TimeUnit.SECONDS)); // Return false after two seconds

    }
}

2, SynchronousQueue

characteristic

Only one element is allowed in the SynchronousQueue queue. Only when the element is taken out of the queue can it be put in again. Look at the code below. You can run and feel it yourself.

public class BlockQueueDemo1 {
    public static void main(String[] args) throws InterruptedException {
        // Create blocking queue
        BlockingQueue<String> blockingQueue = new SynchronousQueue<>();

        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + " >>> put");
                blockingQueue.put("1");
                System.out.println(Thread.currentThread().getName() + " >>> put");
                blockingQueue.put("2");
                System.out.println(Thread.currentThread().getName() + " >>> put");
                blockingQueue.put("3");
            }catch (Exception e) {
                e.printStackTrace();
            }
        },"A").start();

        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println(blockingQueue.take());
                TimeUnit.SECONDS.sleep(2);
                System.out.println(blockingQueue.take());
                TimeUnit.SECONDS.sleep(2);
                System.out.println(blockingQueue.take());
            }catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();

    }
}

2, Use

Take the producer consumer example to write a demo of the blocking queue. The scenario is that the producer produces one per second and the consumer consumes one per second. The two are executed alternately for 5 seconds.

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class BlockQueueDemo2 {
    public static void main(String[] args) throws InterruptedException {
        MyResource myResource = new MyResource(new ArrayBlockingQueue(10));

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "Production thread start");
            try {
                myResource.myProd();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"prod").start();

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "Consumer thread start");
            try {
                myResource.myConsumer();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"consumer").start();

        TimeUnit.SECONDS.sleep(5);
        System.out.println("main Thread stop");

        myResource.stop();

    }
}

class MyResource {
    private volatile boolean FLAG = true;
    private AtomicInteger num = new AtomicInteger();
    private BlockingQueue<String> blockQueue;

    public MyResource(BlockingQueue blockQueue) {
        this.blockQueue = blockQueue;
        System.out.println(blockQueue.getClass().getName());
    }

    public void myProd () throws InterruptedException {
        String data;
        boolean retValue;
        while (FLAG) {
            data = num.incrementAndGet() + "";
            retValue = blockQueue.offer(data, 2L, TimeUnit.SECONDS);
            if (retValue) {
                System.out.println(Thread.currentThread().getName() + "Insert queue"+ data +"success");
            } else {
                System.out.println(Thread.currentThread().getName() + "Insert queue"+ data +"fail");
            }
            TimeUnit.SECONDS.sleep(1);
        }
        System.out.println(Thread.currentThread().getName() + "The main program stops, indicating FLAG=false, End of production action");
    }


    public void myConsumer () throws InterruptedException {
        String result = null;
        while (FLAG) {
            result = blockQueue.poll(2L, TimeUnit.SECONDS);
            if (result == null || result.equalsIgnoreCase("")) {
                FLAG = false;
                System.out.println(Thread.currentThread().getName() + "No consumption for more than two seconds, exit");
                return;
            }
            System.out.println(Thread.currentThread().getName() + "Consumption queue"+ result +"success");
        }
        System.out.println(Thread.currentThread().getName() + "The main program stops, indicating FLAG=false, End of production action");
    }

    public void stop () {
        this.FLAG = false;
    }
}


Posted by AustinP on Sun, 24 Oct 2021 23:20:30 -0700