1. Queue + blocking queue
(1) Blocking queue, as its name implies, is a queue, and the role of a blocking queue in the data structure is roughly shown in the following figure:
When the blocking queue is empty, the operation of getting elements from the queue will be blocked.
When the blocking queue is full, the operation of adding elements to the queue will be blocked.
Threads trying to get elements from an empty blocking queue will be blocked until other threads insert new elements into the queue.
Similarly, a thread trying to add a new element to a full blocking queue will be blocked until another thread removes one or more elements from the queue or completely empties the queue, and the queue will become idle again and added subsequently.
2. Why? What are the benefits
In the multithreading field: for all blocking, the thread will be suspended (i.e. blocking) in some cases. Once the conditions are met, the suspended thread will be awakened automatically.
Why BlockingQueue
The advantage is that we don't need to care when we need to block the thread and wake up the thread, because all this is done by BlockingQueue
Before the release of concurrent package, in a multithreaded environment, each programmer must control this detail, especially considering efficiency and thread safety, which will bring great complexity to our program.
3. Architecture combing + Category Analysis
(1)ArrayBlockingQueue: a bounded blocking queue composed of an array structure
(2)LinkedBlockingQueue: a bounded (default size is Integer.MAX_VALUE=2147483647) blocking queue composed of linked list structure
(3)SynchronousQueue: does not store blocking queues for elements or queues for individual elements
(4)PriorityBlockingQueue: an unbounded blocking queue that supports prioritization
(5)DelayQueue: delay unbounded blocking queue implemented using priority queue
(6)LinkedTransferQueue: an unbounded blocking queue composed of a linked list structure
(7)LinkedBlockingDeque: bidirectional unbounded blocking queue composed of linked list structure
case
package register; import java.util.Collection; import java.util.Queue; import java.util.concurrent.*; /** * ArrayBlockingQueue:It is a bounded blocking queue based on array. The secondary queue sorts the elements according to the FIFO (first in first out) principle * LinkedBlockingQueue:A blocking queue based on linked list structure. The secondary queue sorts the elements according to FIFO (first in first out). The throughput is usually higher than that of ArrayBlockingQueue * SynchronousQueue:A blocking queue that does not store elements. Each insert operation must wait until another thread calls the remove operation. Otherwise, the insert operation is always blocked, and the throughput is usually higher than * * * Blocking queue * */ public class BlockingQueueDemo { public static void main(String[] args) { BlockingQueue<String> blockingQueue=new SynchronousQueue<>(); new Thread(()->{ try { System.out.println(Thread.currentThread().getName()+"\t put 1"); blockingQueue.put("1"); System.out.println(Thread.currentThread().getName()+"\t put 2"); blockingQueue.put("2"); System.out.println(Thread.currentThread().getName()+"\t put 3"); blockingQueue.put("3"); }catch (Exception e){ e.printStackTrace(); } },"t1").start(); new Thread(()->{ try { try{TimeUnit.SECONDS.sleep(5);}catch (Exception e){e.printStackTrace();} System.out.println(Thread.currentThread().getName()+"\t "+blockingQueue.take()); try{TimeUnit.SECONDS.sleep(5);}catch (Exception e){e.printStackTrace();} System.out.println(Thread.currentThread().getName()+"\t "+blockingQueue.take()); try{TimeUnit.SECONDS.sleep(5);}catch (Exception e){e.printStackTrace();} System.out.println(Thread.currentThread().getName()+"\t "+blockingQueue.take()); }catch (Exception e){ e.printStackTrace(); } },"t2").start(); } } //output t1 put 1 t2 get 1 t1 put 2 t2 get 2 t1 put 3 t2 get 3
4.BlockingQueue core method
5. Where is it used
(1) Producer consumer model
// Traditional edition
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class ShareData{//Resource class private int number=0; private Lock lock=new ReentrantLock(); private Condition condition=lock.newCondition(); //addition public void increment() throws Exception{ lock.lock(); try { // 1. Judgment while (number!=0){ //Waiting, unable to produce condition.await(); } //work number++; System.out.println(Thread.currentThread().getName()+"\t "+number); //Notification wake up condition.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } //subtraction public void decrement() throws Exception{ lock.lock(); try { // 1. Judgment while (number==0){ //Waiting, unable to produce condition.await(); } //work number--; System.out.println(Thread.currentThread().getName()+"\t "+number); //Notification wake up condition.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } /** * Title: for a variable with an initial value of 0, two threads operate alternately, one plus 1 and one minus 1, for 5 rounds * Thread operation resource class * Work judgment notice * Anti false wake-up mechanism */ public class ProdConsumer_TraditionDemo { public static void main(String[] args) { ShareData shareData=new ShareData(); new Thread(()->{ for (int i = 1; i <=5 ; i++) { try { shareData.increment(); } catch (Exception e) { e.printStackTrace(); } } },"t1").start(); new Thread(()->{ for (int i = 1; i <=5 ; i++) { try { shareData.decrement(); } catch (Exception e) { e.printStackTrace(); } } },"t2").start(); } } //Output information t1 1 t2 0 t1 1 t2 0 t1 1 t2 0 t1 1 t2 0 t1 1 t2 0
// Blocking queue version
package register; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; class MyResource { /** * The interaction of production and consumption is enabled by default */ private volatile boolean flag = true; /** * The default value is 0 */ private AtomicInteger atomicInteger = new AtomicInteger(); private BlockingQueue<String> blockingQueue = null; public MyResource(BlockingQueue<String> blockingQueue) { this.blockingQueue = blockingQueue; System.out.println(blockingQueue.getClass().getName()); } public void myProd() throws Exception { String data = null; boolean returnValue; while (flag) { data = atomicInteger.incrementAndGet() + ""; returnValue = blockingQueue.offer(data, 2L, TimeUnit.SECONDS); if (returnValue) { System.out.println(Thread.currentThread().getName() + "\t Insert queue data" + data + "success"); } else { System.out.println(Thread.currentThread().getName() + "\t Insert queue data" + data + "fail"); } TimeUnit.SECONDS.sleep(1); } System.out.println(Thread.currentThread().getName() + "\t Stop representation flag" + flag); } public void myConsumer() throws Exception { String result = null; while (flag) { result = blockingQueue.poll(2L, TimeUnit.SECONDS); if(null==result||"".equalsIgnoreCase(result)){ flag=false; System.out.println(Thread.currentThread().getName()+"\t"+"More than 2 m No consumption withdrawal"); System.out.println(); System.out.println(); return; } System.out.println(Thread.currentThread().getName() + "Consumption queue" + result + "success"); } } public void stop() throws Exception{ flag=false; } } public class ProdConsumerBlockQueueDemo { public static void main(String[] args) throws Exception { MyResource myResource = new MyResource(new ArrayBlockingQueue<>(10)); new Thread(()->{ System.out.println(Thread.currentThread().getName()+"\t Production thread start"); try { myResource.myProd(); } catch (Exception e) { e.printStackTrace(); } },"Prod").start(); new Thread(()->{ System.out.println(Thread.currentThread().getName()+"\t Consumer thread start"); try { myResource.myConsumer(); } catch (Exception e) { e.printStackTrace(); } },"consumer").start(); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(); System.out.println(); System.out.println(); System.out.println("Time out,Stop activity"); myResource.stop(); } }