BarrierConsumer.java revision f252dc7a25ba08b973ecc1cfbbce58eb78d42167
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
17package com.android.quicksearchbox.util;
18
19import java.util.ArrayList;
20import java.util.concurrent.TimeUnit;
21import java.util.concurrent.locks.Condition;
22import java.util.concurrent.locks.Lock;
23import java.util.concurrent.locks.ReentrantLock;
24
25/**
26 * A consumer that consumes a fixed number of values. When the expected number of values
27 * has been consumed, further values are rejected.
28 */
29public class BarrierConsumer<A> implements Consumer<A> {
30
31    private final Lock mLock = new ReentrantLock();
32    private final Condition mNotFull = mLock.newCondition();
33
34    private final int mExpectedCount;
35
36    // Set to null when getValues() returns.
37    private ArrayList<A> mValues;
38
39    /**
40     * Constructs a new BarrierConsumer.
41     *
42     * @param expectedCount The number of values to consume.
43     */
44    public BarrierConsumer(int expectedCount) {
45        mExpectedCount = expectedCount;
46        mValues = new ArrayList<A>(expectedCount);
47    }
48
49    /**
50     * Blocks until the expected number of results is available, or until the thread is
51     * interrupted. This method should not be called multiple times.
52     *
53     * @return A list of values, never {@code null}.
54     */
55    public ArrayList<A> getValues() {
56        return getValues(0);
57    }
58
59    /**
60     * Blocks until the expected number of results is available, or until the
61     * timeout has passed, or until the thread is interrupted.
62     * This method should not be called multiple times.
63     *
64     * @return A list of values, never {@code null}.
65     */
66    public ArrayList<A> getValues(long millis) {
67        mLock.lock();
68        try {
69            try {
70                while (!isFull()) {
71                    mNotFull.await(millis, TimeUnit.MILLISECONDS);
72                }
73            } catch (InterruptedException ex) {
74                // Return the values that we've gotten so far
75            }
76            ArrayList<A> values = mValues;
77            mValues = null;  // mark that getValues() has returned
78            return values;
79        } finally {
80            mLock.unlock();
81        }
82    }
83
84    public boolean consume(A value) {
85        mLock.lock();
86        try {
87            // Do nothing if getValues() has alrady returned,
88            // or enough values have already been consumed
89            if (mValues == null || isFull()) {
90                return false;
91            }
92            mValues.add(value);
93            if (isFull()) {
94                // Wake up any thread waiting in getValues()
95                mNotFull.signal();
96            }
97            return true;
98        } finally {
99            mLock.unlock();
100        }
101    }
102
103    private boolean isFull() {
104        return mValues.size() == mExpectedCount;
105    }
106}
107