1.ArrayBlockingQueue介绍
1.1BlockingQueue Interface
Supports blocking waiting queues: When removing the element, if the queue is empty, wait until the queue is not empty; when the storage element, if the queue is full, wait until the queue idle.
For BlockingQueue, performing operations when the conditions are not met, there are four forms.
|
Throws exception |
Special value |
Blocks |
Times out |
Insert |
(If the queue is not full, adding, return true; If the queue is full, throw IllegalStateException) |
(If the queue is not full, adding, return true; If the queue is full, return false) |
(If the queue is not full, adding, no return value; If the queue is full, wait until the queue has idle) |
(If the queue is not full, adding, return true; If the queue is full, wait after a specified time or full queue, returns false) |
Remove |
(If the queue is not empty, removal, return true; If the queue is empty, return false) |
(If the queue is not empty, remove; If the queue is empty, return null) |
(If the queue is not empty, remove; If the queue is empty, wait until the queue is not empty) |
(If the queue is not empty, remove; If the queue is empty, a specified time after the wait queue is empty, return null) |
Examine |
not applicable |
not applicable |
Use the sample - typically (and more) producers, (multi) Consumer Model
// producer thread class Producer the implements the Runnable { Private Final BlockingQueue Queue; // blocking queue Producer (BlockingQueue Q) = {Queue Q;} public void RUN () { the try { the while ( to true ) {queue.put (Produce () );} // production, incorporating team } the catch (InterruptedException EX) {... handle ...} } Object produce () {...} } // consumer thread class consumer the implements Runnable { Private Final BlockingQueue Queue; // blocking queue Consumer (BlockingQueue Q) = {Queue Q;} public void RUN () { the try { the while ( to true ) {Consume (queue.take ());} // dequeued consumption } the catch (InterruptedException EX) ... handle {...} } void Consume (Object X) {...} } class the Setup { void main () { BlockingQueue Q = new new SomeQueueImplementation (); // start producers 1 thread, two consumer threads Producer p =new Producer(q); Consumer c1 = new Consumer(q); Consumer c2 = new Consumer(q); new Thread(p).start(); new Thread(c1).start(); new Thread(c2).start(); } }
1.2ArrayBlockingQueue
ArrayBlockingQueue array is implemented thread safe bounded blocking queue.
1. Array Implementation: array implemented using a circular queue.
2. Thread safety: Use a ReentrantLock to ensure thread safety.
3. Bounded: a fixed number of elements may be stored. Due to internal array realization, once created, can not change the length of the array.
4. blocking queue: FIFO. When taken out of the element, if the queue is empty, wait until the queue is not empty; when the storage element, if the queue is full, wait until the queue is idle.
2.ArrayBlockingQueue source code analysis
2.1 Create
public ArrayBlockingQueue with ( int Capacity, Boolean Fair) { IF (Capacity <= 0 ) the throw new new an IllegalArgumentException (); the this .items = new new Object [Capacity]; // array storage elements Lock = new new of ReentrantLock (Fair); // lock guarantee security thread notEmpty = lock.newCondition (); notFull = lock.newCondition (); }
2.2 Producer Consumer Model
2.2.1 producers to produce elements --put method element into the team
put method
How to achieve synchronization between threads [producer] and [consumer]
1. If the queue is full, call notFull.await () method, the current thread is blocked waiting for [producer]
2. After the element into the team, calling notEmpty.signal () method, Wake blocked [consumer] thread
// inserts the specified element to the tail of the queue // If the queue is full, the current thread to wait until the queue is idle public void PUT (E E) throws InterruptedException { checkNotNull (E); Final of ReentrantLock = Lock the this .lock; // get lock lock.lockInterruptibly (); the try { // If the queue is full, the current thread to wait until the queue has idle the while (COUNT == items.length) notFull.await (); // queue has idle elements into the team enqueue (e ); } the finally { // release lock lock.unlock (); } } Private void the enqueue (E X) { // Assert lock.getHoldCount () ==. 1; // Assert items [putIndex] == null; // element into the team Final Object [] items = the this .items; items [putIndex] = the X-; IF (++ putIndex == items.length) putIndex = 0 ; COUNT ++ ; // wake-up thread blocked on notEmepty notEmpty.signal (); }
2.2.2 --take consumer spending element method element from the team
take method
How to achieve [producer] and [consumer] Thread Synchronization
1. If the queue is empty, call notEmpty.await () method, the current thread is blocked waiting for [consumer]
2. After the element into the team, calling notFull.signal () method, Wake blocked [producer] thread
// Returns the element head of the queue // if the queue is empty, waiting until the queue is not empty public E Take () throws InterruptedException { Final of ReentrantLock = Lock the this .lock; // get the lock lock.lockInterruptibly (); the try { / / If the queue is empty, waiting until the queue is not empty the while (COUNT == 0 ) notEmpty.await (); // queue is not empty, return the head elements return dequeue (); } the finally { // release lock lock.unlock (); } } Private E dequeue () { //lock.getHoldCount Assert () ==. 1; // Assert items [takeIndex] = null;! // return the head elements Final Object [] items = the this .items; @SuppressWarnings ( "an unchecked" ) E X = (E) items [takeIndex]; items [takeIndex] = null ; IF (++ takeIndex == items.length) takeIndex = 0 ; COUNT - ; IF (the ITRS =! null ) itrs.elementDequeued (); // wake-up blocked notFull threads on notFull.signal (); return x; }