### **JUC LinkedBlockingQueue**
java.util.concurrent.LinkedBlockingQueue是一個基于單向鏈表,范圍任意的(其實是有界的),FIFO阻塞隊列。訪問與移除操作是在隊頭進行,添加操作是在隊尾進行,并分別使用不同的鎖進行保護,只有在可能涉及多個節點的操作才同時對兩個鎖進行加鎖,
隊列是否為空,是否已滿任然是通過元素數量的計算器,(count)進行判斷,由于可以同時在隊頭,隊尾并發地進行訪問,添加操作,所以這個計數器必須是線程安全的,這里使用了一個原子類,AtomicInteger,這就決定了它的容量范圍是1-integer.MAX_VALUE.。
### **源碼解析**
```
//內部構造方法
public LinkedBlockingQueue(){
this(Integer.MAX_VALUE);
}
```
實例化時如果未給初始控制值,則按照Integer最大值(2的31次方-1)去走
當實例化時給了一個初始化空間值。
~~~
//內部構造方法
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);
}
~~~
當capacity的值等于或者小于0時,則拋出IllegalArgumentException,最后鏈表的隊頭和隊尾都初始化為空。
## **在說第三個構造函數時,先看一下ReentrantLock是什么東西,跟synchronized有什么區別**
1. synchronized是獨占鎖,加鎖和解鎖的過程是自動進行,易于操作,但不夠靈活。
ReentrantLock也是獨占鎖,加鎖和解鎖的過程是手動進行,不易于操作,但非常靈活
2. synchronized是可重入鎖,以為加鎖和解鎖是自動進行,不必擔心最后是否釋放鎖;
ReentrantLock也可重入鎖,但加鎖和解鎖是手動進行,且次數需一樣,否則其他線程無法得到鎖。
3. Synchronized不可響應中斷,一個線程獲取不到鎖就一直等著;
ReentrantLock可以響應中斷
使用:
```
private static final Lock lock = new ReentrantLock();
public static void main(String[] args) {
new Thread( ()-> test(),"線程A").start();
new Thread( ()-> test(),"線程B").start();
}
public static void test(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"獲取了鎖");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName()+"釋放了鎖");
lock.unlock();
}
}
```
執行結果是:
```
線程A獲取了鎖
線程A釋放了鎖
線程B獲取了鎖
線程B釋放了鎖
```
看一下把test方法加上synchronized 注釋掉lock.lock()和lock.unlock() 其執行結果是一致的,那不同點在哪呢?那就是公平鎖的實現。
```
private static final Lock lock = new ReentrantLock(true);
public static void main(String[] args) {
new Thread( ()-> test(),"線程A").start();
new Thread( ()-> test(),"線程B").start();
new Thread( ()-> test(),"線程C").start();
}
public static void test(){
for(int i =0;i<2;i++){
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"獲取了鎖");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName()+"釋放了鎖");
lock.unlock();
}
}
}
```
在初始化時加上了公平鎖策略,構造參數值為true
上面代碼執行結果如下列:
左邊是使用ReentranyLock鎖,右邊是使用synchronized

使用ReentranLock公平鎖,會按照順序執行。
非公平鎖:
非公平鎖那就隨機的獲取,看cpu時間片輪到哪個線程,哪個線程就能獲取鎖,和上面公平鎖的區別很簡單,就在于實例化時構造參數為false或者true,默認為false。
響應中斷:
響應中斷就是一個線程獲取不到鎖,不會一直等下去,Reentranlock會給予一個中斷回應。看下面代碼:
```
public class aaa {
static final Lock lock = new ReentrantLock();
static final Lock lock1 = new ReentrantLock();
public static void main(String[] args) {
Thread thread = new Thread(new ThreadA(lock,lock1));
Thread thread1 = new Thread(new ThreadA(lock,lock1));
thread.start();
thread1.start();
thread.interrupt();
}
}
class ThreadA implements Runnable{
Lock firstLock;
Lock sencondLock;
public ThreadA(Lock firstLock,Lock sencondLock){
this.firstLock = firstLock;
this.sencondLock = sencondLock;
}
@Override
public void run() {
try {
firstLock.lockInterruptibly();
TimeUnit.SECONDS.sleep(5);
sencondLock.lockInterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
firstLock.unlock();
sencondLock.unlock();
System.out.println(Thread.currentThread().getName()+"獲取到了資源,正常結束");
}
}
}
```
定義了兩個鎖,lock和lock1,然后使用兩個線程thread和thread1造成是說場景。正常情況下,這兩個線程相互等待獲取資源而處于死循環狀態。但是thread中斷,另外一個線程就可以獲取到資源,正常執行,
限時等待:
通過tryLock方法來實現,可以選擇傳入時間參數,表示等待指定的時間,無參則表示立即返回鎖申請的結果,true表示獲取鎖成功,false表示獲取鎖失敗,可以用這種發放解決死鎖的問題。
### **回到原文**
```
//LinkedBlockingQueue第三構造方法
public LinkedBlockingQueue(Collection<? extends E> c) {
this(Integer.MAX_VALUE);
final ReentrantLock putLock = this.putLock;
putLock.lock(); // Never contended, but necessary for visibility
try {
int n = 0;
for (E e : c) {
if (e == null)
throw new NullPointerException();
if (n == capacity)
throw new IllegalStateException("Queue full");
enqueue(new Node<E>(e));
++n;
}
count.set(n);
} finally {
putLock.unlock();
}
}
```
傳入一個集合,創建一個容量為這個集合的LinkedBlockingQueue,并且按照集合迭代器順序添加。
這里使用ReentranLock鎖來實現同步并且線程安全。
初始化給了Integer的最大值。并創建了一個鎖,并鎖當前方法
迭代傳入的集合,當集合內的元素為null時 拋出一個空指針異常。當計數類的數值等于數組內的元素的個數時,會拋出Queue Full 異常。<br/><br/>
```
public int size() {
return count.get();
}
```
獲取當前已使用的容量。是通過原子類AtomicInteger的get方法獲取<br/><br/>
~~~
public int remainingCapacity() {
return capacity - count.get();
}
~~~
獲取剩余容量,是通過最大的容量減已使用的容量<br/><br/>
~~~
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
int c = -1;
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
while (count.get() == capacity) {
notFull.await();
}
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
}
~~~
在隊列的尾部添加元素
未寫完。。。。。。。。(2020年03月24日16:50)
- JDK常用知識庫
- JDK各個版本安裝
- Java8流
- 算法
- 十大排序算法
- 冒泡排序
- 選擇排序
- 插入排序
- 歸并排序
- 快速排序
- 堆排序
- 希爾排序
- 計數排序
- 桶排序
- 基數排序
- 總結
- 常用工具類
- 浮點型計算
- 時間格式處理
- 常用功能點思路整理
- 登錄
- 高并發
- 線程安全的單例模式
- Tomcat優化
- Tomcat之APR模式
- Tomcat啟動過慢問題
- 常用的數據庫連接池
- Druid連接池
- 緩存
- Redis
- SpringBoot整合Redis
- 依賴和配置
- RedisTemplate工具類
- 工具類使用方法
- Redis知識庫
- Redis安裝
- Redis配置參數
- Redis常用Lua腳本
- MongoDB
- SpringBoot操作MongoDB
- 依賴和配置
- MongoDB工具類
- 工具類使用方法
- 消息中間件
- ActiveMq
- SpringBoot整合ActiveMq
- 框架
- SpringBoot
- 定時任務
- 啟動加載
- 事務
- JSP
- 靜態類注入
- SpringSecurity
- Shiro
- 配置及整合
- 登陸驗證
- 權限驗證
- 分布式應用
- SpringMVC
- ORM框架
- Mybatis
- 增
- 刪
- 改
- 查
- 程序員小笑話
- 我給你講一個TCP的笑話吧
- 二進制笑話
- JavaScript的那點東西
- JavaScript內置對象及常見API詳細介紹
- JavaScript實現Ajax 資源請求
- JavaScript干貨
- 架構師成長之路
- JDK源碼解析
- ArrayList源碼解讀
- 設計模式
- 微服務架構設計模式
- 逃離單體煉獄
- 服務的拆分策略
- 全面解析SpringMvc框架
- 架構設計的六大原則
- 并發集合
- JUC并發編程
- 搜索引擎
- Solr
- Solr的安裝
- 分布式服務框架
- Dubbo
- 從零開始學HTMl
- 第一章-初識HTML
- 第二章-認識HTML標簽