SynchronousQueue和LinkedBlockingQueue區別
阿新 • • 發佈:2018-12-14
在多執行緒開發中,會用到SynchronousQueue(new CachedThreadPool())和LinkedBlockingQueue(new FixedThreadPoll())
我們來簡單分析一下這兩個佇列的區別
SynchronousQueue:
offer():當執行緒offer操作時,當same mode時,加入佇列失敗,即時返回 (如果是put操作,元素會儲存到佇列中,並且阻塞等待);
當complimentary mode時,立即把元素transfer給等待的take執行緒
take():執行緒take操作,當same mode時,該執行緒把元素儲存到佇列中,並且阻塞等待(如果是poll操作,元素會加入佇列失敗,即時返回);
當complimentary mode時,立即在佇列中找到等待的put執行緒關聯的元素,取出來,返回
LinkedBlockingQueue
offer(): 執行緒把元素放入佇列中(多執行緒併發競爭),返回,超過bound,返回失敗
1 /** Lock held by take, poll, etc */ 2 private final ReentrantLock takeLock = new ReentrantLock(); 3 4 /** Wait queue for waiting takes */ 5 privateoffer方法final Condition notEmpty = takeLock.newCondition(); 6 7 /** Lock held by put, offer, etc */ 8 private final ReentrantLock putLock = new ReentrantLock(); 9 10 /** Wait queue for waiting puts */ 11 private final Condition notFull = putLock.newCondition(); 12 13 14 public boolean offer(E e) {15 if (e == null) throw new NullPointerException(); 16 final AtomicInteger count = this.count; 17 if (count.get() == capacity) 18 return false; 19 int c = -1; 20 Node<E> node = new Node<E>(e); 21 final ReentrantLock putLock = this.putLock; 22 putLock.lock(); 23 try { 24 if (count.get() < capacity) { 25 enqueue(node); 26 c = count.getAndIncrement(); 27 if (c + 1 < capacity) 28 notFull.signal(); 29 } 30 } finally { 31 putLock.unlock(); 32 } 33 if (c == 0) 34 signalNotEmpty(); 35 return c >= 0; 36 }
take(); 佇列不為空時,獲取元素(多執行緒併發競爭),為空時,阻塞等待
1 public E take() throws InterruptedException { 2 E x; 3 int c = -1; 4 final AtomicInteger count = this.count; 5 final ReentrantLock takeLock = this.takeLock; 6 takeLock.lockInterruptibly(); 7 try { 8 while (count.get() == 0) { 9 notEmpty.await(); 10 } 11 x = dequeue(); 12 c = count.getAndDecrement(); 13 if (c > 1) 14 notEmpty.signal(); 15 } finally { 16 takeLock.unlock(); 17 } 18 if (c == capacity) 19 signalNotFull(); 20 return x; 21 }View Code
設想一種場景:
當有大量執行緒在offer和take時,
1、LinkedBlockingQueue在入隊和出隊時,併發競爭激烈,cpu執行緒切換頻繁,效能較低;
2、SynchronousQueue中每一個元素對應一個put執行緒、一個take執行緒,不會存在鎖競爭
但是反過來 SynchronousQueue需要的執行緒數較多,如果take消費不及時,會導致put執行緒阻塞(如果是使用offer的話,會加入佇列失敗)