佇列、阻塞佇列
佇列
佇列是一種先入先出的資料結構,新加入的元素都是加入到佇列的後面
阻塞佇列
java.util.concurrent.BlockingQueue<E>,是一種支援阻塞的插入元素,阻塞的移除元素操作的佇列。
阻塞的插入:當佇列空間滿了,阻塞執行緒繼續向佇列中新增元素
阻塞的移除:當佇列空間空了,阻塞執行緒從佇列中取出元素
從這裡看出,阻塞佇列可以用在生產者/消費者模型中,生產者是向佇列中新增元素的執行緒,消費者是從佇列中取出元素的執行緒
*佇列的操作方法
方法 | 丟擲異常 | 返回特殊值 | 一直阻塞 | 超時退出 |
插入 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
移除 | remove() | poll | take | poll(time,unit) |
檢查方法 | element() | peek() | / | / |
丟擲異常:指的是佇列滿了或者佇列為空,就丟擲異常
返回特殊值:指的是插入方法返回的是true/false,移除方法返回的是元素
一直阻塞:指的是如果佇列滿了,再呼叫方法向佇列中新增,生產者執行緒會一直阻塞,佇列空了,再從佇列中取元素,消費者執行緒會一直阻塞
超時退出:同樣是對於上面的情況,來說,不過是超出了時間,執行緒就會退出
* 如果是無界佇列,插入的put,offer一定不會阻塞,而且offer返回true
阻塞佇列BlockQueue的實現類
1 . ArrayBlockingQueue
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
/** The queued items */
final Object[] items;
/** items index for next take, poll, peek or remove */
int takeIndex;
/** items index for next put, offer, or add */
int putIndex;
/** Number of elements in the queue */
int count;
/** Main lock guarding all access */
final ReentrantLock lock;
/** Condition for waiting takes */
private final Condition notEmpty;
/** Condition for waiting puts */
private final Condition notFull;
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
* 建立時候,必須指定容量大小/可以指定公平性,內部以陣列進行存放
* 只有一個重入鎖,意味著,生產者消費者呼叫時候,一個阻塞,一個執行,無法並行執行
2 . LinkedBlockingDeque
public class LinkedBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
/**
* Linked list node class
*/
static class Node<E> {
E item;
Node<E> next;
Node(E x) { item = x; }
}
/** The capacity bound, or Integer.MAX_VALUE if none */
private final int capacity;
/** Current number of elements */
private final AtomicInteger count = new AtomicInteger(0);
/**
* Head of linked list.
* Invariant: head.item == null
*/
private transient Node<E> head;
/**
* Tail of linked list.
* Invariant: last.next == null
*/
private transient Node<E> last;
/** Lock held by take, poll, etc */
private final ReentrantLock takeLock = new ReentrantLock();
/** Wait queue for waiting takes */
private final Condition notEmpty = takeLock.newCondition();
/** Lock held by put, offer, etc */
private final ReentrantLock putLock = new ReentrantLock();
/** Wait queue for waiting puts */
private final Condition notFull = putLock.newCondition();
/**
* Signals a waiting take. Called only from put/offer (which do not
* otherwise ordinarily lock takeLock.)
*/
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
/**
* Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity.
*
* @param capacity the capacity of this queue
* @throws IllegalArgumentException if {@code capacity} is not greater
* than zero
*/
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);
}
* LinkedBlockingQueue的建立可以指定容量大小,預設是Integer.MAX_VALUE,可以認為是無界的
* 存放元素的結構,是以連結串列存放
* 生產者和消費者執行緒,持有的ReentrantLock是不同的,意味著生產者執行緒和消費者執行緒可以並行執行
,通過檢查count,完成阻塞消費者或者生產者的動作
3.SynchronousQueue
和前面兩種佇列實現不同的,這個佇列本身不會去存放元素,每一個put操作,必須等待另一個take操作,否則就不能繼續新增元素
/**
* Creates a <tt>SynchronousQueue</tt> with nonfair access policy.
*/
public SynchronousQueue() {
this(false);
}
/**
* Creates a <tt>SynchronousQueue</tt> with the specified fairness policy.
*
* @param fair if true, waiting threads contend in FIFO order for
* access; otherwise the order is unspecified.
*/
public SynchronousQueue(boolean fair) {
transferer = fair ? new TransferQueue() : new TransferStack();
}
* 可以指定執行緒訪問的策略,如果是true,按照先進先出來訪問佇列,否則就是非公平的,預設是非公平的
等待通知機制,自定義一個阻塞佇列
使用陣列實現一個阻塞佇列 https://blog.csdn.net/ditto_zhou/article/details/77330733
使用阻塞佇列來實現生產者消費模型
package com.ftf.thread.lock;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
public class ProductCustomerDemo {
private static AtomicInteger ai = new AtomicInteger();
public static void main(String[] args) {
final ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<Integer>(10);
Thread product = new Thread(new Runnable() {
@Override
public void run() {
while(true){
try {
int a = ai.incrementAndGet();
System.out.println("生產者生產資料:"+a);
abq.put(a);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread customer = new Thread(new Runnable() {
@Override
public void run() {
while(true){
try {
int a = abq.take();
System.out.println("消費者取資料"+a);
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
product.start();
customer.start();
}
}
當達到容量上限制後,生產者停止生產資料,直到消費者消費,容量減少,繼續生產,在非單個生產者-消費者模型中,不用擔心出現執行緒假死的現象。
相關文章
- 阻塞佇列一——java中的阻塞佇列佇列Java
- 阻塞佇列--LinkedBlockingQueue佇列BloC
- 阻塞佇列 BlockingQueue佇列BloC
- 死磕阻塞佇列佇列
- Java中的阻塞佇列Java佇列
- 阻塞佇列——四組API佇列API
- 延遲阻塞佇列 DelayQueue佇列
- 阻塞佇列BlockingQueue(三)--DelayQueue佇列BloC
- 聊聊併發(四)——阻塞佇列佇列
- 阻塞佇列 SynchronousQueue 原始碼解析佇列原始碼
- 阻塞佇列 LinkedTransferQueue 原始碼解析佇列原始碼
- 阻塞佇列 DelayQueue 原始碼解析佇列原始碼
- 阻塞佇列 PriorityBlockingQueue 原始碼解析佇列BloC原始碼
- 佇列-單端佇列佇列
- 處理線上RabbitMQ佇列阻塞MQ佇列
- 阻塞佇列 BlockingQueue(二)--ArrayBlockingQueue與LinkedBlockingQueue佇列BloC
- Java併發系列 — 阻塞佇列(BlockingQueue)Java佇列BloC
- Java併發——阻塞佇列集(上)Java佇列
- Java併發——阻塞佇列集(下)Java佇列
- 什麼是阻塞佇列?如何使用阻塞佇列來實現生產者-消費者模型?佇列模型
- 【佇列】【懶排序】佇列Q佇列排序
- 佇列 和 迴圈佇列佇列
- 陣列模擬佇列 以及佇列的複用(環形佇列)陣列佇列
- JAVA併發之阻塞佇列淺析Java佇列
- JAVA中常見的阻塞佇列詳解Java佇列
- Java併發程式設計——阻塞佇列Java程式設計佇列
- Java併發程式設計:阻塞佇列Java程式設計佇列
- Android併發學習之阻塞佇列Android佇列
- 佇列 手算到機算 入門 佇列 迴圈佇列佇列
- 單調佇列雙端佇列佇列
- 圖解--佇列、併發佇列圖解佇列
- 佇列佇列
- 面經手冊 · 第9篇《佇列是什麼?什麼是雙端佇列、延遲對列、阻塞佇列,全是知識盲區!》佇列
- Kafka 延時佇列&重試佇列Kafka佇列
- RabbitMQ 訊息佇列之佇列模型MQ佇列模型
- JDK中有直接可以使用的阻塞佇列JDK佇列
- 基於promise的阻塞式佇列設計Promise佇列
- 迴歸Java基礎:LinkedBlockingQueue阻塞佇列解析JavaBloC佇列