ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/experimental/server/Queue/Queue.java
Revision: 1.2
Committed: Thu Dec 28 03:49:15 2000 UTC (23 years, 11 months ago) by tdb
Branch: MAIN
Changes since 1.1: +193 -23 lines
Log Message:
Added support for multiple consumers.

File Contents

# Content
1 //---PACKAGE DECLARATION---
2
3 //---IMPORTS---
4 import java.util.LinkedList;
5 import java.util.NoSuchElementException;
6 //import uk.ac.ukc.iscream.util.*;
7
8 /**
9 * A Queue class designed to operate in a multi-threaded environment, with
10 * added support for multiple "consumer" threads. Also offers blocking on
11 * the get() methods, which ensures the consumer waits until the queue
12 * actually contains some elements.
13 *
14 * @author $Author$
15 * @version $Id$
16 */
17 class Queue {
18
19 //---FINAL ATTRIBUTES---
20
21 /**
22 * The current CVS revision of this class
23 */
24 public static final String REVISION = "$Revision: 1.1 $";
25
26 //---STATIC METHODS---
27
28 //---CONSTRUCTORS---
29
30 /**
31 * This constructor sets up a given number of queues, all of which
32 * will be populated with data using the add() method. It is very
33 * important that the correct number is given, otherwise redundant
34 * queues will build up with large amounts of data in them.
35 *
36 * @param consumers The number of queues to be created.
37 */
38 public Queue(int consumers) {
39 // constuct and initialise the queues
40 _lists = new LinkedList[consumers];
41 for(int i=0; i < _lists.length; i++) {
42 _lists[i] = new LinkedList();
43 }
44 }
45
46 /**
47 * This constructor is intended for an environment with a single
48 * consumer. This should be used in conjunction with the no-args
49 * get() method.
50 */
51 public Queue() {
52 // call the proper constructor
53 this(1);
54 }
55
56 //---PUBLIC METHODS---
57
58 /**
59 * This method adds a given object to every queue. It will notify
60 * any waiting consumers (on an empty queue) during this process.
61 *
62 * @param o An Object to be added to the queues.
63 */
64 public void add(Object o) {
65 for(int i=0; i < _lists.length; i++) {
66 int s = _lists[i].size();
67 synchronized(this) {
68 // add() does the same thing, but this ensures behaviour
69 _lists[i].addLast(o);
70 }
71 // if the queue was empty before the add it is possible
72 // that a consumer is waiting... so we notify them
73 if (s == 0) {
74 synchronized(_lists[i]) {
75 _lists[i].notifyAll();
76 }
77 }
78 }
79 // we keep track of the total additions for the status() method
80 _count++;
81 }
82
83 /**
84 * This method returns an object from the front of a given queue.
85 * It will block until data exists in the queue if required.
86 *
87 * @return The object from the front of the queue.
88 */
89 public Object get(int queue) {
90 // block if the queue is empty
91 if (_lists[queue].size() == 0) {
92 synchronized(_lists[queue]) {
93 try { _lists[queue].wait(); } catch(Exception e) {}
94 }
95 }
96 // get an item, it should never be null due to the blocking above
97 Object o = null;
98 synchronized(this) {
99 try {
100 o = _lists[queue].removeFirst();
101 }
102 catch (NoSuchElementException e) {
103 // This should never happen !
104 }
105 }
106 return o;
107 }
108
109 /**
110 * This method is intended for an environment where there is
111 * only a single consumer. It simply gets the item from the
112 * first (and presumably only) queue.
113 *
114 * @return The object from the front of the queue.
115 */
116 public Object get() {
117 return get(0);
118 }
119
120 /**
121 * This method returns a textual status of the queues. It
122 * is merely for observation, and would most likely be used
123 * by a larger "monitoring" component. Information returned
124 * includes the current size of each queue, and the total
125 * items passed through.
126 *
127 * @return A String message containing status information.
128 */
129 public String status() {
130 String status = "";
131 for(int i=0; i < _lists.length; i++) {
132 status += "Queue number "+i+" contains "+_lists[i].size()+" elements";
133 status += "\n";
134 }
135 status += "A total of "+_count+" elements have been added to the queues";
136 return status;
137 }
138
139 /**
140 * This method assigns a queue to a consumer. The idea behind
141 * this is to ensure that only 1 consumer can be associated with
142 * a given queue, otherwise the whole "blocking" thing fails
143 * miserably.
144 *
145 * @return An integer to be passed to the get() method.
146 * @throws NoQueueException if there are no un-assigned queue's.
147 */
148 public int getQueue() throws NoQueueException {
149 if(_index < _lists.length) {
150 return _index++;
151 }
152 else {
153 throw new NoQueueException("Too many consumers, there are already "+_lists.length+" running");
154 }
155 }
156
157 /**
158 * Overrides the {@link java.lang.Object#toString() Object.toString()}
159 * method to provide clean logging (every class should have this).
160 *
161 * This uses the uk.ac.ukc.iscream.util.FormatName class
162 * to format the toString()
163 *
164 * @return the name of this class and its CVS revision
165 */
166 /*public String toString() {
167 return FormatName.getName(
168 _name,
169 getClass().getName(),
170 REVISION);
171 }*/
172
173 //---PRIVATE METHODS---
174
175 //---ACCESSOR/MUTATOR METHODS---
176
177 //---ATTRIBUTES---
178
179 /**
180 * The array of lists, which the underlying queue data
181 * is stored in.
182 */
183 private LinkedList[] _lists;
184
185 /**
186 * A counter so we know how many data items have been
187 * passed through, for statistical purposes.
188 */
189 private int _count = 0;
190
191 /**
192 * An index of the next available queue. Used by the
193 * getQueue() method.
194 */
195 private int _index = 0;
196
197 /**
198 * This is the friendly identifier of the
199 * component this class is running in.
200 * eg, a Filter may be called "filter1",
201 * If this class does not have an owning
202 * component, a name from the configuration
203 * can be placed here. This name could also
204 * be changed to null for utility classes.
205 */
206 //private String _name = <!THIS SHOULD CALL A STATIC NAME IN THE COMPONENT CLASS FOR THIS OBJECT!>;
207
208 /**
209 * This holds a reference to the
210 * system logger that is being used.
211 */
212 //private Logger _logger = ReferenceManager.getInstance().getLogger();
213
214 //---STATIC ATTRIBUTES---
215
216 }