1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.quicksearchbox.util;
18 
19 import java.util.ArrayList;
20 import java.util.concurrent.locks.Condition;
21 import java.util.concurrent.locks.Lock;
22 import java.util.concurrent.locks.ReentrantLock;
23 
24 /**
25  * A consumer that consumes a fixed number of values. When the expected number of values
26  * has been consumed, further values are rejected.
27  */
28 public class BarrierConsumer<A> implements Consumer<A> {
29 
30     private final Lock mLock = new ReentrantLock();
31     private final Condition mNotFull = mLock.newCondition();
32 
33     private final int mExpectedCount;
34 
35     // Set to null when getValues() returns.
36     private ArrayList<A> mValues;
37 
38     /**
39      * Constructs a new BarrierConsumer.
40      *
41      * @param expectedCount The number of values to consume.
42      */
BarrierConsumer(int expectedCount)43     public BarrierConsumer(int expectedCount) {
44         mExpectedCount = expectedCount;
45         mValues = new ArrayList<A>(expectedCount);
46     }
47 
48     /**
49      * Blocks until the expected number of results is available, or until the thread is
50      * interrupted. This method should not be called multiple times.
51      *
52      * @return A list of values, never {@code null}.
53      */
getValues()54     public ArrayList<A> getValues() {
55         mLock.lock();
56         try {
57             try {
58                 while (!isFull()) {
59                     mNotFull.await();
60                 }
61             } catch (InterruptedException ex) {
62                 // Return the values that we've gotten so far
63             }
64             ArrayList<A> values = mValues;
65             mValues = null;  // mark that getValues() has returned
66             return values;
67         } finally {
68             mLock.unlock();
69         }
70     }
71 
consume(A value)72     public boolean consume(A value) {
73         mLock.lock();
74         try {
75             // Do nothing if getValues() has alrady returned,
76             // or enough values have already been consumed
77             if (mValues == null || isFull()) {
78                 return false;
79             }
80             mValues.add(value);
81             if (isFull()) {
82                 // Wake up any thread waiting in getValues()
83                 mNotFull.signal();
84             }
85             return true;
86         } finally {
87             mLock.unlock();
88         }
89     }
90 
isFull()91     private boolean isFull() {
92         return mValues.size() == mExpectedCount;
93     }
94 }
95