() {
75 | @Override
76 | public boolean test(Message message) {
77 | boolean shouldRemove = message.target == h && (object == null || message.obj == object);
78 | if(shouldRemove){
79 | message.recycleUnchecked();
80 | }
81 | return shouldRemove;
82 | }
83 | });
84 | }
85 |
86 | void quit(boolean safe) {
87 | if (isQuited) return;
88 | isQuited = true;
89 | Logger.debug("Quit, messages in queue: " + queue.size());
90 | if (!safe) {
91 | queue.clear();
92 | }
93 | // Tell looper to quit.
94 | POISON.when = System.currentTimeMillis();
95 | POISON.who = "KILLER";
96 | Logger.debug("Feed poison: %s", POISON);
97 | queue.offer(POISON);
98 | }
99 | }
--------------------------------------------------------------------------------
/src/main/java/android/os/internal/DelayQueue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
3 | *
4 | *
5 | *
6 | *
7 | *
8 | *
9 | *
10 | *
11 | *
12 | *
13 | *
14 | *
15 | *
16 | *
17 | *
18 | *
19 | *
20 | *
21 | *
22 | *
23 | */
24 |
25 | /*
26 | *
27 | *
28 | *
29 | *
30 | *
31 | * Written by Doug Lea with assistance from members of JCP JSR-166
32 | * Expert Group and released to the public domain, as explained at
33 | * http://creativecommons.org/publicdomain/zero/1.0/
34 | */
35 |
36 | package android.os.internal;
37 |
38 | import java.util.AbstractQueue;
39 | import java.util.Collection;
40 | import java.util.Iterator;
41 | import java.util.NoSuchElementException;
42 | import java.util.Objects;
43 | import java.util.concurrent.BlockingQueue;
44 | import java.util.concurrent.TimeUnit;
45 | import java.util.concurrent.locks.Condition;
46 | import java.util.concurrent.locks.ReentrantLock;
47 | import java.util.function.Predicate;
48 |
49 | import static java.util.concurrent.TimeUnit.NANOSECONDS;
50 |
51 | /**
52 | * An unbounded {@linkplain BlockingQueue blocking queue} of
53 | * {@code Delayed} elements, in which an element can only be taken
54 | * when its delay has expired. The head of the queue is that
55 | * {@code Delayed} element whose delay expired furthest in the
56 | * past. If no delay has expired there is no head and {@code poll}
57 | * will return {@code null}. Expiration occurs when an element's
58 | * {@code getDelay(TimeUnit.NANOSECONDS)} method returns a value less
59 | * than or equal to zero. Even though unexpired elements cannot be
60 | * removed using {@code take} or {@code poll}, they are otherwise
61 | * treated as normal elements. For example, the {@code size} method
62 | * returns the count of both expired and unexpired elements.
63 | * This queue does not permit null elements.
64 | *
65 | * This class and its iterator implement all of the
66 | * optional methods of the {@link Collection} and {@link
67 | * Iterator} interfaces. The Iterator provided in method {@link
68 | * #iterator()} is not guaranteed to traverse the elements of
69 | * the DelayQueue in any particular order.
70 | *
71 | *
This class is a member of the
72 | *
73 | * Java Collections Framework.
74 | *
75 | * @since 1.5
76 | * @author Doug Lea
77 | * @param the type of elements held in this collection
78 | */
79 | public class DelayQueue extends AbstractQueue
80 | implements BlockingQueue {
81 |
82 | private final transient ReentrantLock lock = new ReentrantLock();
83 | private final PriorityQueue q = new PriorityQueue();
84 |
85 | /**
86 | * Thread designated to wait for the element at the head of
87 | * the queue. This variant of the Leader-Follower pattern
88 | * (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to
89 | * minimize unnecessary timed waiting. When a thread becomes
90 | * the leader, it waits only for the next delay to elapse, but
91 | * other threads await indefinitely. The leader thread must
92 | * signal some other thread before returning from take() or
93 | * poll(...), unless some other thread becomes leader in the
94 | * interim. Whenever the head of the queue is replaced with
95 | * an element with an earlier expiration time, the leader
96 | * field is invalidated by being reset to null, and some
97 | * waiting thread, but not necessarily the current leader, is
98 | * signalled. So waiting threads must be prepared to acquire
99 | * and lose leadership while waiting.
100 | */
101 | private Thread leader = null;
102 |
103 | /**
104 | * Condition signalled when a newer element becomes available
105 | * at the head of the queue or a new thread may need to
106 | * become leader.
107 | */
108 | private final Condition available = lock.newCondition();
109 |
110 | /**
111 | * Creates a new {@code DelayQueue} that is initially empty.
112 | */
113 | public DelayQueue() {}
114 |
115 | /**
116 | * Creates a {@code DelayQueue} initially containing the elements of the
117 | * given collection of {@link Delayed} instances.
118 | *
119 | * @param c the collection of elements to initially contain
120 | * @throws NullPointerException if the specified collection or any
121 | * of its elements are null
122 | */
123 | public DelayQueue(Collection extends E> c) {
124 | this.addAll(c);
125 | }
126 |
127 | /**
128 | * Inserts the specified element into this delay queue.
129 | *
130 | * @param e the element to add
131 | * @return {@code true} (as specified by {@link Collection#add})
132 | * @throws NullPointerException if the specified element is null
133 | */
134 | public boolean add(E e) {
135 | return offer(e);
136 | }
137 |
138 | /**
139 | * Inserts the specified element into this delay queue.
140 | *
141 | * @param e the element to add
142 | * @return {@code true}
143 | * @throws NullPointerException if the specified element is null
144 | */
145 | public boolean offer(E e) {
146 | final ReentrantLock lock = this.lock;
147 | lock.lock();
148 | try {
149 | q.offer(e);
150 | if (q.peek() == e) {
151 | leader = null;
152 | available.signal();
153 | }
154 | return true;
155 | } finally {
156 | lock.unlock();
157 | }
158 | }
159 |
160 | /**
161 | * Inserts the specified element into this delay queue. As the queue is
162 | * unbounded this method will never block.
163 | *
164 | * @param e the element to add
165 | * @throws NullPointerException {@inheritDoc}
166 | */
167 | public void put(E e) {
168 | offer(e);
169 | }
170 |
171 | /**
172 | * Inserts the specified element into this delay queue. As the queue is
173 | * unbounded this method will never block.
174 | *
175 | * @param e the element to add
176 | * @param timeout This parameter is ignored as the method never blocks
177 | * @param unit This parameter is ignored as the method never blocks
178 | * @return {@code true}
179 | * @throws NullPointerException {@inheritDoc}
180 | */
181 | public boolean offer(E e, long timeout, TimeUnit unit) {
182 | return offer(e);
183 | }
184 |
185 | /**
186 | * Retrieves and removes the head of this queue, or returns {@code null}
187 | * if this queue has no elements with an expired delay.
188 | *
189 | * @return the head of this queue, or {@code null} if this
190 | * queue has no elements with an expired delay
191 | */
192 | public E poll() {
193 | final ReentrantLock lock = this.lock;
194 | lock.lock();
195 | try {
196 | E first = q.peek();
197 | if (first == null || first.getDelay(NANOSECONDS) > 0)
198 | return null;
199 | else
200 | return q.poll();
201 | } finally {
202 | lock.unlock();
203 | }
204 | }
205 |
206 | /**
207 | * Retrieves and removes the head of this queue, waiting if necessary
208 | * until an element with an expired delay is available on this queue.
209 | *
210 | * @return the head of this queue
211 | * @throws InterruptedException {@inheritDoc}
212 | */
213 | public E take() throws InterruptedException {
214 | final ReentrantLock lock = this.lock;
215 | lock.lockInterruptibly();
216 | try {
217 | for (;;) {
218 | E first = q.peek();
219 | if (first == null)
220 | available.await();
221 | else {
222 | long delay = first.getDelay(NANOSECONDS);
223 | if (delay <= 0)
224 | return q.poll();
225 | first = null; // don't retain ref while waiting
226 | if (leader != null)
227 | available.await();
228 | else {
229 | Thread thisThread = Thread.currentThread();
230 | leader = thisThread;
231 | try {
232 | available.awaitNanos(delay);
233 | } finally {
234 | if (leader == thisThread)
235 | leader = null;
236 | }
237 | }
238 | }
239 | }
240 | } finally {
241 | if (leader == null && q.peek() != null)
242 | available.signal();
243 | lock.unlock();
244 | }
245 | }
246 |
247 | /**
248 | * Retrieves and removes the head of this queue, waiting if necessary
249 | * until an element with an expired delay is available on this queue,
250 | * or the specified wait time expires.
251 | *
252 | * @return the head of this queue, or {@code null} if the
253 | * specified waiting time elapses before an element with
254 | * an expired delay becomes available
255 | * @throws InterruptedException {@inheritDoc}
256 | */
257 | public E poll(long timeout, TimeUnit unit) throws InterruptedException {
258 | long nanos = unit.toNanos(timeout);
259 | final ReentrantLock lock = this.lock;
260 | lock.lockInterruptibly();
261 | try {
262 | for (;;) {
263 | E first = q.peek();
264 | if (first == null) {
265 | if (nanos <= 0)
266 | return null;
267 | else
268 | nanos = available.awaitNanos(nanos);
269 | } else {
270 | long delay = first.getDelay(NANOSECONDS);
271 | if (delay <= 0)
272 | return q.poll();
273 | if (nanos <= 0)
274 | return null;
275 | first = null; // don't retain ref while waiting
276 | if (nanos < delay || leader != null)
277 | nanos = available.awaitNanos(nanos);
278 | else {
279 | Thread thisThread = Thread.currentThread();
280 | leader = thisThread;
281 | try {
282 | long timeLeft = available.awaitNanos(delay);
283 | nanos -= delay - timeLeft;
284 | } finally {
285 | if (leader == thisThread)
286 | leader = null;
287 | }
288 | }
289 | }
290 | }
291 | } finally {
292 | if (leader == null && q.peek() != null)
293 | available.signal();
294 | lock.unlock();
295 | }
296 | }
297 |
298 | /**
299 | * Retrieves, but does not remove, the head of this queue, or
300 | * returns {@code null} if this queue is empty. Unlike
301 | * {@code poll}, if no expired elements are available in the queue,
302 | * this method returns the element that will expire next,
303 | * if one exists.
304 | *
305 | * @return the head of this queue, or {@code null} if this
306 | * queue is empty
307 | */
308 | public E peek() {
309 | final ReentrantLock lock = this.lock;
310 | lock.lock();
311 | try {
312 | return q.peek();
313 | } finally {
314 | lock.unlock();
315 | }
316 | }
317 |
318 | public int size() {
319 | final ReentrantLock lock = this.lock;
320 | lock.lock();
321 | try {
322 | return q.size();
323 | } finally {
324 | lock.unlock();
325 | }
326 | }
327 |
328 | /**
329 | * Returns first element only if it is expired.
330 | * Used only by drainTo. Call only when holding lock.
331 | */
332 | private E peekExpired() {
333 | // assert lock.isHeldByCurrentThread();
334 | E first = q.peek();
335 | return (first == null || first.getDelay(NANOSECONDS) > 0) ?
336 | null : first;
337 | }
338 |
339 | /**
340 | * @throws UnsupportedOperationException {@inheritDoc}
341 | * @throws ClassCastException {@inheritDoc}
342 | * @throws NullPointerException {@inheritDoc}
343 | * @throws IllegalArgumentException {@inheritDoc}
344 | */
345 | public int drainTo(Collection super E> c) {
346 | if (c == null)
347 | throw new NullPointerException();
348 | if (c == this)
349 | throw new IllegalArgumentException();
350 | final ReentrantLock lock = this.lock;
351 | lock.lock();
352 | try {
353 | int n = 0;
354 | for (E e; (e = peekExpired()) != null;) {
355 | c.add(e); // In this order, in case add() throws.
356 | q.poll();
357 | ++n;
358 | }
359 | return n;
360 | } finally {
361 | lock.unlock();
362 | }
363 | }
364 |
365 | /**
366 | * @throws UnsupportedOperationException {@inheritDoc}
367 | * @throws ClassCastException {@inheritDoc}
368 | * @throws NullPointerException {@inheritDoc}
369 | * @throws IllegalArgumentException {@inheritDoc}
370 | */
371 | public int drainTo(Collection super E> c, int maxElements) {
372 | if (c == null)
373 | throw new NullPointerException();
374 | if (c == this)
375 | throw new IllegalArgumentException();
376 | if (maxElements <= 0)
377 | return 0;
378 | final ReentrantLock lock = this.lock;
379 | lock.lock();
380 | try {
381 | int n = 0;
382 | for (E e; n < maxElements && (e = peekExpired()) != null;) {
383 | c.add(e); // In this order, in case add() throws.
384 | q.poll();
385 | ++n;
386 | }
387 | return n;
388 | } finally {
389 | lock.unlock();
390 | }
391 | }
392 |
393 | /**
394 | * Atomically removes all of the elements from this delay queue.
395 | * The queue will be empty after this call returns.
396 | * Elements with an unexpired delay are not waited for; they are
397 | * simply discarded from the queue.
398 | */
399 | public void clear() {
400 | final ReentrantLock lock = this.lock;
401 | lock.lock();
402 | try {
403 | q.clear();
404 | } finally {
405 | lock.unlock();
406 | }
407 | }
408 |
409 | /**
410 | * Always returns {@code Integer.MAX_VALUE} because
411 | * a {@code DelayQueue} is not capacity constrained.
412 | *
413 | * @return {@code Integer.MAX_VALUE}
414 | */
415 | public int remainingCapacity() {
416 | return Integer.MAX_VALUE;
417 | }
418 |
419 | /**
420 | * Returns an array containing all of the elements in this queue.
421 | * The returned array elements are in no particular order.
422 | *
423 | * The returned array will be "safe" in that no references to it are
424 | * maintained by this queue. (In other words, this method must allocate
425 | * a new array). The caller is thus free to modify the returned array.
426 | *
427 | *
This method acts as bridge between array-based and collection-based
428 | * APIs.
429 | *
430 | * @return an array containing all of the elements in this queue
431 | */
432 | public Object[] toArray() {
433 | final ReentrantLock lock = this.lock;
434 | lock.lock();
435 | try {
436 | return q.toArray();
437 | } finally {
438 | lock.unlock();
439 | }
440 | }
441 |
442 | /**
443 | * Returns an array containing all of the elements in this queue; the
444 | * runtime type of the returned array is that of the specified array.
445 | * The returned array elements are in no particular order.
446 | * If the queue fits in the specified array, it is returned therein.
447 | * Otherwise, a new array is allocated with the runtime type of the
448 | * specified array and the size of this queue.
449 | *
450 | *
If this queue fits in the specified array with room to spare
451 | * (i.e., the array has more elements than this queue), the element in
452 | * the array immediately following the end of the queue is set to
453 | * {@code null}.
454 | *
455 | *
Like the {@link #toArray()} method, this method acts as bridge between
456 | * array-based and collection-based APIs. Further, this method allows
457 | * precise control over the runtime type of the output array, and may,
458 | * under certain circumstances, be used to save allocation costs.
459 | *
460 | *
The following code can be used to dump a delay queue into a newly
461 | * allocated array of {@code Delayed}:
462 | *
463 | *
{@code Delayed[] a = q.toArray(new Delayed[0]);}
464 | *
465 | * Note that {@code toArray(new Object[0])} is identical in function to
466 | * {@code toArray()}.
467 | *
468 | * @param a the array into which the elements of the queue are to
469 | * be stored, if it is big enough; otherwise, a new array of the
470 | * same runtime type is allocated for this purpose
471 | * @return an array containing all of the elements in this queue
472 | * @throws ArrayStoreException if the runtime type of the specified array
473 | * is not a supertype of the runtime type of every element in
474 | * this queue
475 | * @throws NullPointerException if the specified array is null
476 | */
477 | public T[] toArray(T[] a) {
478 | final ReentrantLock lock = this.lock;
479 | lock.lock();
480 | try {
481 | return q.toArray(a);
482 | } finally {
483 | lock.unlock();
484 | }
485 | }
486 |
487 | /**
488 | * Removes a single instance of the specified element from this
489 | * queue, if it is present, whether or not it has expired.
490 | */
491 | public boolean remove(Object o) {
492 | final ReentrantLock lock = this.lock;
493 | lock.lock();
494 | try {
495 | return q.remove(o);
496 | } finally {
497 | lock.unlock();
498 | }
499 | }
500 |
501 | @Override
502 | public boolean removeIf(Predicate super E> filter) {
503 | Objects.requireNonNull(filter);
504 | final ReentrantLock lock = this.lock;
505 | lock.lock();
506 | try {
507 | boolean removed = false;
508 | final Iterator each = q.iterator();
509 | while (each.hasNext()) {
510 | if (filter.test(each.next())) {
511 | each.remove();
512 | removed = true;
513 | }
514 | }
515 | return removed;
516 | } finally {
517 | lock.unlock();
518 | }
519 | }
520 |
521 | /**
522 | * Identity-based version for use in Itr.remove
523 | */
524 | void removeEQ(Object o) {
525 | final ReentrantLock lock = this.lock;
526 | lock.lock();
527 | try {
528 | for (Iterator it = q.iterator(); it.hasNext(); ) {
529 | if (o == it.next()) {
530 | it.remove();
531 | break;
532 | }
533 | }
534 | } finally {
535 | lock.unlock();
536 | }
537 | }
538 |
539 | /**
540 | * Returns an iterator over all the elements (both expired and
541 | * unexpired) in this queue. The iterator does not return the
542 | * elements in any particular order.
543 | *
544 | * The returned iterator is
545 | * weakly consistent.
546 | *
547 | * @return an iterator over the elements in this queue
548 | */
549 | public Iterator iterator() {
550 | return new Itr(toArray());
551 | }
552 |
553 | /**
554 | * Snapshot iterator that works off copy of underlying q array.
555 | */
556 | private class Itr implements Iterator {
557 | final Object[] array; // Array of all elements
558 | int cursor; // index of next element to return
559 | int lastRet; // index of last element, or -1 if no such
560 |
561 | Itr(Object[] array) {
562 | lastRet = -1;
563 | this.array = array;
564 | }
565 |
566 | public boolean hasNext() {
567 | return cursor < array.length;
568 | }
569 |
570 | @SuppressWarnings("unchecked")
571 | public E next() {
572 | if (cursor >= array.length)
573 | throw new NoSuchElementException();
574 | lastRet = cursor;
575 | return (E)array[cursor++];
576 | }
577 |
578 | public void remove() {
579 | if (lastRet < 0)
580 | throw new IllegalStateException();
581 | removeEQ(array[lastRet]);
582 | lastRet = -1;
583 | }
584 | }
585 |
586 | }
587 |
--------------------------------------------------------------------------------
/src/main/java/android/os/internal/Delayed.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
3 | *
4 | *
5 | *
6 | *
7 | *
8 | *
9 | *
10 | *
11 | *
12 | *
13 | *
14 | *
15 | *
16 | *
17 | *
18 | *
19 | *
20 | *
21 | *
22 | *
23 | */
24 |
25 | /*
26 | *
27 | *
28 | *
29 | *
30 | *
31 | * Written by Doug Lea with assistance from members of JCP JSR-166
32 | * Expert Group and released to the public domain, as explained at
33 | * http://creativecommons.org/publicdomain/zero/1.0/
34 | */
35 |
36 | package android.os.internal;
37 |
38 | import java.util.concurrent.TimeUnit;
39 |
40 | /**
41 | * A mix-in style interface for marking objects that should be
42 | * acted upon after a given delay.
43 | *
44 | * An implementation of this interface must define a
45 | * {@code compareTo} method that provides an ordering consistent with
46 | * its {@code getDelay} method.
47 | *
48 | * @since 1.5
49 | * @author Doug Lea
50 | */
51 | public interface Delayed extends Comparable {
52 |
53 | /**
54 | * Returns the remaining delay associated with this object, in the
55 | * given time unit.
56 | *
57 | * @param unit the time unit
58 | * @return the remaining delay; zero or negative values indicate
59 | * that the delay has already elapsed
60 | */
61 | long getDelay(TimeUnit unit);
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/android/os/internal/PriorityQueue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3 | * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4 | *
5 | *
6 | *
7 | *
8 | *
9 | *
10 | *
11 | *
12 | *
13 | *
14 | *
15 | *
16 | *
17 | *
18 | *
19 | *
20 | *
21 | *
22 | *
23 | *
24 | */
25 |
26 | package android.os.internal;
27 |
28 | import java.util.AbstractQueue;
29 | import java.util.ArrayDeque;
30 | import java.util.Arrays;
31 | import java.util.Collection;
32 | import java.util.Comparator;
33 | import java.util.ConcurrentModificationException;
34 | import java.util.Iterator;
35 | import java.util.NoSuchElementException;
36 | import java.util.Queue;
37 | import java.util.SortedSet;
38 | import java.util.Spliterator;
39 | import java.util.function.Consumer;
40 |
41 | /**
42 | * An unbounded priority {@linkplain Queue queue} based on a priority heap.
43 | * The elements of the priority queue are ordered according to their
44 | * {@linkplain Comparable natural ordering}, or by a {@link Comparator}
45 | * provided at queue construction time, depending on which constructor is
46 | * used. A priority queue does not permit {@code null} elements.
47 | * A priority queue relying on natural ordering also does not permit
48 | * insertion of non-comparable objects (doing so may result in
49 | * {@code ClassCastException}).
50 | *
51 | * The head of this queue is the least element
52 | * with respect to the specified ordering. If multiple elements are
53 | * tied for least value, the head is one of those elements -- ties are
54 | * broken arbitrarily. The queue retrieval operations {@code poll},
55 | * {@code remove}, {@code peek}, and {@code element} access the
56 | * element at the head of the queue.
57 | *
58 | *
A priority queue is unbounded, but has an internal
59 | * capacity governing the size of an array used to store the
60 | * elements on the queue. It is always at least as large as the queue
61 | * size. As elements are added to a priority queue, its capacity
62 | * grows automatically. The details of the growth policy are not
63 | * specified.
64 | *
65 | *
This class and its iterator implement all of the
66 | * optional methods of the {@link Collection} and {@link
67 | * Iterator} interfaces. The Iterator provided in method {@link
68 | * #iterator()} is not guaranteed to traverse the elements of
69 | * the priority queue in any particular order. If you need ordered
70 | * traversal, consider using {@code Arrays.sort(pq.toArray())}.
71 | *
72 | *
Note that this implementation is not synchronized.
73 | * Multiple threads should not access a {@code PriorityQueue}
74 | * instance concurrently if any of the threads modifies the queue.
75 | * Instead, use the thread-safe {@link
76 | * java.util.concurrent.PriorityBlockingQueue} class.
77 | *
78 | *
Implementation note: this implementation provides
79 | * O(log(n)) time for the enqueuing and dequeuing methods
80 | * ({@code offer}, {@code poll}, {@code remove()} and {@code add});
81 | * linear time for the {@code remove(Object)} and {@code contains(Object)}
82 | * methods; and constant time for the retrieval methods
83 | * ({@code peek}, {@code element}, and {@code size}).
84 | *
85 | *
This class is a member of the
86 | *
87 | * Java Collections Framework.
88 | *
89 | * @since 1.5
90 | * @author Josh Bloch, Doug Lea
91 | * @param the type of elements held in this collection
92 | */
93 | public class PriorityQueue extends AbstractQueue
94 | implements java.io.Serializable {
95 |
96 | private static final long serialVersionUID = -7720805057305804111L;
97 |
98 | private static final int DEFAULT_INITIAL_CAPACITY = 11;
99 |
100 | /**
101 | * Priority queue represented as a balanced binary heap: the two
102 | * children of queue[n] are queue[2*n+1] and queue[2*(n+1)]. The
103 | * priority queue is ordered by comparator, or by the elements'
104 | * natural ordering, if comparator is null: For each node n in the
105 | * heap and each descendant d of n, n <= d. The element with the
106 | * lowest value is in queue[0], assuming the queue is nonempty.
107 | */
108 | transient Object[] queue; // non-private to simplify nested class access
109 |
110 | /**
111 | * The number of elements in the priority queue.
112 | */
113 | private int size = 0;
114 |
115 | /**
116 | * The comparator, or null if priority queue uses elements'
117 | * natural ordering.
118 | */
119 | private final Comparator super E> comparator;
120 |
121 | /**
122 | * The number of times this priority queue has been
123 | * structurally modified. See AbstractList for gory details.
124 | */
125 | transient int modCount = 0; // non-private to simplify nested class access
126 |
127 | /**
128 | * Creates a {@code PriorityQueue} with the default initial
129 | * capacity (11) that orders its elements according to their
130 | * {@linkplain Comparable natural ordering}.
131 | */
132 | public PriorityQueue() {
133 | this(DEFAULT_INITIAL_CAPACITY, null);
134 | }
135 |
136 | /**
137 | * Creates a {@code PriorityQueue} with the specified initial
138 | * capacity that orders its elements according to their
139 | * {@linkplain Comparable natural ordering}.
140 | *
141 | * @param initialCapacity the initial capacity for this priority queue
142 | * @throws IllegalArgumentException if {@code initialCapacity} is less
143 | * than 1
144 | */
145 | public PriorityQueue(int initialCapacity) {
146 | this(initialCapacity, null);
147 | }
148 |
149 | /**
150 | * Creates a {@code PriorityQueue} with the default initial capacity and
151 | * whose elements are ordered according to the specified comparator.
152 | *
153 | * @param comparator the comparator that will be used to order this
154 | * priority queue. If {@code null}, the {@linkplain Comparable
155 | * natural ordering} of the elements will be used.
156 | * @since 1.8
157 | */
158 | public PriorityQueue(Comparator super E> comparator) {
159 | this(DEFAULT_INITIAL_CAPACITY, comparator);
160 | }
161 |
162 | /**
163 | * Creates a {@code PriorityQueue} with the specified initial capacity
164 | * that orders its elements according to the specified comparator.
165 | *
166 | * @param initialCapacity the initial capacity for this priority queue
167 | * @param comparator the comparator that will be used to order this
168 | * priority queue. If {@code null}, the {@linkplain Comparable
169 | * natural ordering} of the elements will be used.
170 | * @throws IllegalArgumentException if {@code initialCapacity} is
171 | * less than 1
172 | */
173 | public PriorityQueue(int initialCapacity,
174 | Comparator super E> comparator) {
175 | // Note: This restriction of at least one is not actually needed,
176 | // but continues for 1.5 compatibility
177 | if (initialCapacity < 1)
178 | throw new IllegalArgumentException();
179 | this.queue = new Object[initialCapacity];
180 | this.comparator = comparator;
181 | }
182 |
183 | /**
184 | * Creates a {@code PriorityQueue} containing the elements in the
185 | * specified collection. If the specified collection is an instance of
186 | * a {@link SortedSet} or is another {@code PriorityQueue}, this
187 | * priority queue will be ordered according to the same ordering.
188 | * Otherwise, this priority queue will be ordered according to the
189 | * {@linkplain Comparable natural ordering} of its elements.
190 | *
191 | * @param c the collection whose elements are to be placed
192 | * into this priority queue
193 | * @throws ClassCastException if elements of the specified collection
194 | * cannot be compared to one another according to the priority
195 | * queue's ordering
196 | * @throws NullPointerException if the specified collection or any
197 | * of its elements are null
198 | */
199 | @SuppressWarnings("unchecked")
200 | public PriorityQueue(Collection extends E> c) {
201 | if (c instanceof SortedSet>) {
202 | SortedSet extends E> ss = (SortedSet extends E>) c;
203 | this.comparator = (Comparator super E>) ss.comparator();
204 | initElementsFromCollection(ss);
205 | }
206 | else if (c instanceof PriorityQueue>) {
207 | PriorityQueue extends E> pq = (PriorityQueue extends E>) c;
208 | this.comparator = (Comparator super E>) pq.comparator();
209 | initFromPriorityQueue(pq);
210 | }
211 | else {
212 | this.comparator = null;
213 | initFromCollection(c);
214 | }
215 | }
216 |
217 | /**
218 | * Creates a {@code PriorityQueue} containing the elements in the
219 | * specified priority queue. This priority queue will be
220 | * ordered according to the same ordering as the given priority
221 | * queue.
222 | *
223 | * @param c the priority queue whose elements are to be placed
224 | * into this priority queue
225 | * @throws ClassCastException if elements of {@code c} cannot be
226 | * compared to one another according to {@code c}'s
227 | * ordering
228 | * @throws NullPointerException if the specified priority queue or any
229 | * of its elements are null
230 | */
231 | @SuppressWarnings("unchecked")
232 | public PriorityQueue(PriorityQueue extends E> c) {
233 | this.comparator = (Comparator super E>) c.comparator();
234 | initFromPriorityQueue(c);
235 | }
236 |
237 | /**
238 | * Creates a {@code PriorityQueue} containing the elements in the
239 | * specified sorted set. This priority queue will be ordered
240 | * according to the same ordering as the given sorted set.
241 | *
242 | * @param c the sorted set whose elements are to be placed
243 | * into this priority queue
244 | * @throws ClassCastException if elements of the specified sorted
245 | * set cannot be compared to one another according to the
246 | * sorted set's ordering
247 | * @throws NullPointerException if the specified sorted set or any
248 | * of its elements are null
249 | */
250 | @SuppressWarnings("unchecked")
251 | public PriorityQueue(SortedSet extends E> c) {
252 | this.comparator = (Comparator super E>) c.comparator();
253 | initElementsFromCollection(c);
254 | }
255 |
256 | private void initFromPriorityQueue(PriorityQueue extends E> c) {
257 | if (c.getClass() == PriorityQueue.class) {
258 | this.queue = c.toArray();
259 | this.size = c.size();
260 | } else {
261 | initFromCollection(c);
262 | }
263 | }
264 |
265 | private void initElementsFromCollection(Collection extends E> c) {
266 | Object[] a = c.toArray();
267 | // If c.toArray incorrectly doesn't return Object[], copy it.
268 | if (a.getClass() != Object[].class)
269 | a = Arrays.copyOf(a, a.length, Object[].class);
270 | int len = a.length;
271 | if (len == 1 || this.comparator != null)
272 | for (int i = 0; i < len; i++)
273 | if (a[i] == null)
274 | throw new NullPointerException();
275 | this.queue = a;
276 | this.size = a.length;
277 | }
278 |
279 | /**
280 | * Initializes queue array with elements from the given Collection.
281 | *
282 | * @param c the collection
283 | */
284 | private void initFromCollection(Collection extends E> c) {
285 | initElementsFromCollection(c);
286 | heapify();
287 | }
288 |
289 | /**
290 | * The maximum size of array to allocate.
291 | * Some VMs reserve some header words in an array.
292 | * Attempts to allocate larger arrays may result in
293 | * OutOfMemoryError: Requested array size exceeds VM limit
294 | */
295 | private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
296 |
297 | /**
298 | * Increases the capacity of the array.
299 | *
300 | * @param minCapacity the desired minimum capacity
301 | */
302 | private void grow(int minCapacity) {
303 | int oldCapacity = queue.length;
304 | // Double size if small; else grow by 50%
305 | int newCapacity = oldCapacity + ((oldCapacity < 64) ?
306 | (oldCapacity + 2) :
307 | (oldCapacity >> 1));
308 | // overflow-conscious code
309 | if (newCapacity - MAX_ARRAY_SIZE > 0)
310 | newCapacity = hugeCapacity(minCapacity);
311 | queue = Arrays.copyOf(queue, newCapacity);
312 | }
313 |
314 | private static int hugeCapacity(int minCapacity) {
315 | if (minCapacity < 0) // overflow
316 | throw new OutOfMemoryError();
317 | return (minCapacity > MAX_ARRAY_SIZE) ?
318 | Integer.MAX_VALUE :
319 | MAX_ARRAY_SIZE;
320 | }
321 |
322 | /**
323 | * Inserts the specified element into this priority queue.
324 | *
325 | * @return {@code true} (as specified by {@link Collection#add})
326 | * @throws ClassCastException if the specified element cannot be
327 | * compared with elements currently in this priority queue
328 | * according to the priority queue's ordering
329 | * @throws NullPointerException if the specified element is null
330 | */
331 | public boolean add(E e) {
332 | return offer(e);
333 | }
334 |
335 | /**
336 | * Inserts the specified element into this priority queue.
337 | *
338 | * @return {@code true} (as specified by {@link Queue#offer})
339 | * @throws ClassCastException if the specified element cannot be
340 | * compared with elements currently in this priority queue
341 | * according to the priority queue's ordering
342 | * @throws NullPointerException if the specified element is null
343 | */
344 | public boolean offer(E e) {
345 | if (e == null)
346 | throw new NullPointerException();
347 | modCount++;
348 | int i = size;
349 | if (i >= queue.length)
350 | grow(i + 1);
351 | size = i + 1;
352 | if (i == 0)
353 | queue[0] = e;
354 | else
355 | siftUp(i, e);
356 | return true;
357 | }
358 |
359 | @SuppressWarnings("unchecked")
360 | public E peek() {
361 | return (size == 0) ? null : (E) queue[0];
362 | }
363 |
364 | private int indexOf(Object o) {
365 | if (o != null) {
366 | for (int i = 0; i < size; i++)
367 | if (o.equals(queue[i]))
368 | return i;
369 | }
370 | return -1;
371 | }
372 |
373 | /**
374 | * Removes a single instance of the specified element from this queue,
375 | * if it is present. More formally, removes an element {@code e} such
376 | * that {@code o.equals(e)}, if this queue contains one or more such
377 | * elements. Returns {@code true} if and only if this queue contained
378 | * the specified element (or equivalently, if this queue changed as a
379 | * result of the call).
380 | *
381 | * @param o element to be removed from this queue, if present
382 | * @return {@code true} if this queue changed as a result of the call
383 | */
384 | public boolean remove(Object o) {
385 | int i = indexOf(o);
386 | if (i == -1)
387 | return false;
388 | else {
389 | removeAt(i);
390 | return true;
391 | }
392 | }
393 |
394 | /**
395 | * Version of remove using reference equality, not equals.
396 | * Needed by iterator.remove.
397 | *
398 | * @param o element to be removed from this queue, if present
399 | * @return {@code true} if removed
400 | */
401 | boolean removeEq(Object o) {
402 | for (int i = 0; i < size; i++) {
403 | if (o == queue[i]) {
404 | removeAt(i);
405 | return true;
406 | }
407 | }
408 | return false;
409 | }
410 |
411 | /**
412 | * Returns {@code true} if this queue contains the specified element.
413 | * More formally, returns {@code true} if and only if this queue contains
414 | * at least one element {@code e} such that {@code o.equals(e)}.
415 | *
416 | * @param o object to be checked for containment in this queue
417 | * @return {@code true} if this queue contains the specified element
418 | */
419 | public boolean contains(Object o) {
420 | return indexOf(o) != -1;
421 | }
422 |
423 | /**
424 | * Returns an array containing all of the elements in this queue.
425 | * The elements are in no particular order.
426 | *
427 | * The returned array will be "safe" in that no references to it are
428 | * maintained by this queue. (In other words, this method must allocate
429 | * a new array). The caller is thus free to modify the returned array.
430 | *
431 | *
This method acts as bridge between array-based and collection-based
432 | * APIs.
433 | *
434 | * @return an array containing all of the elements in this queue
435 | */
436 | public Object[] toArray() {
437 | return Arrays.copyOf(queue, size);
438 | }
439 |
440 | /**
441 | * Returns an array containing all of the elements in this queue; the
442 | * runtime type of the returned array is that of the specified array.
443 | * The returned array elements are in no particular order.
444 | * If the queue fits in the specified array, it is returned therein.
445 | * Otherwise, a new array is allocated with the runtime type of the
446 | * specified array and the size of this queue.
447 | *
448 | *
If the queue fits in the specified array with room to spare
449 | * (i.e., the array has more elements than the queue), the element in
450 | * the array immediately following the end of the collection is set to
451 | * {@code null}.
452 | *
453 | *
Like the {@link #toArray()} method, this method acts as bridge between
454 | * array-based and collection-based APIs. Further, this method allows
455 | * precise control over the runtime type of the output array, and may,
456 | * under certain circumstances, be used to save allocation costs.
457 | *
458 | *
Suppose {@code x} is a queue known to contain only strings.
459 | * The following code can be used to dump the queue into a newly
460 | * allocated array of {@code String}:
461 | *
462 | *
{@code String[] y = x.toArray(new String[0]);}
463 | *
464 | * Note that {@code toArray(new Object[0])} is identical in function to
465 | * {@code toArray()}.
466 | *
467 | * @param a the array into which the elements of the queue are to
468 | * be stored, if it is big enough; otherwise, a new array of the
469 | * same runtime type is allocated for this purpose.
470 | * @return an array containing all of the elements in this queue
471 | * @throws ArrayStoreException if the runtime type of the specified array
472 | * is not a supertype of the runtime type of every element in
473 | * this queue
474 | * @throws NullPointerException if the specified array is null
475 | */
476 | @SuppressWarnings("unchecked")
477 | public T[] toArray(T[] a) {
478 | final int size = this.size;
479 | if (a.length < size)
480 | // Make a new array of a's runtime type, but my contents:
481 | return (T[]) Arrays.copyOf(queue, size, a.getClass());
482 | System.arraycopy(queue, 0, a, 0, size);
483 | if (a.length > size)
484 | a[size] = null;
485 | return a;
486 | }
487 |
488 | /**
489 | * Returns an iterator over the elements in this queue. The iterator
490 | * does not return the elements in any particular order.
491 | *
492 | * @return an iterator over the elements in this queue
493 | */
494 | public Iterator iterator() {
495 | return new Itr();
496 | }
497 |
498 | private final class Itr implements Iterator {
499 | /**
500 | * Index (into queue array) of element to be returned by
501 | * subsequent call to next.
502 | */
503 | private int cursor = 0;
504 |
505 | /**
506 | * Index of element returned by most recent call to next,
507 | * unless that element came from the forgetMeNot list.
508 | * Set to -1 if element is deleted by a call to remove.
509 | */
510 | private int lastRet = -1;
511 |
512 | /**
513 | * A queue of elements that were moved from the unvisited portion of
514 | * the heap into the visited portion as a result of "unlucky" element
515 | * removals during the iteration. (Unlucky element removals are those
516 | * that require a siftup instead of a siftdown.) We must visit all of
517 | * the elements in this list to complete the iteration. We do this
518 | * after we've completed the "normal" iteration.
519 | *
520 | * We expect that most iterations, even those involving removals,
521 | * will not need to store elements in this field.
522 | */
523 | private ArrayDeque forgetMeNot = null;
524 |
525 | /**
526 | * Element returned by the most recent call to next iff that
527 | * element was drawn from the forgetMeNot list.
528 | */
529 | private E lastRetElt = null;
530 |
531 | /**
532 | * The modCount value that the iterator believes that the backing
533 | * Queue should have. If this expectation is violated, the iterator
534 | * has detected concurrent modification.
535 | */
536 | private int expectedModCount = modCount;
537 |
538 | public boolean hasNext() {
539 | return cursor < size ||
540 | (forgetMeNot != null && !forgetMeNot.isEmpty());
541 | }
542 |
543 | @SuppressWarnings("unchecked")
544 | public E next() {
545 | if (expectedModCount != modCount)
546 | throw new ConcurrentModificationException();
547 | if (cursor < size)
548 | return (E) queue[lastRet = cursor++];
549 | if (forgetMeNot != null) {
550 | lastRet = -1;
551 | lastRetElt = forgetMeNot.poll();
552 | if (lastRetElt != null)
553 | return lastRetElt;
554 | }
555 | throw new NoSuchElementException();
556 | }
557 |
558 | public void remove() {
559 | if (expectedModCount != modCount)
560 | throw new ConcurrentModificationException();
561 | if (lastRet != -1) {
562 | E moved = PriorityQueue.this.removeAt(lastRet);
563 | lastRet = -1;
564 | if (moved == null)
565 | cursor--;
566 | else {
567 | if (forgetMeNot == null)
568 | forgetMeNot = new ArrayDeque<>();
569 | forgetMeNot.add(moved);
570 | }
571 | } else if (lastRetElt != null) {
572 | PriorityQueue.this.removeEq(lastRetElt);
573 | lastRetElt = null;
574 | } else {
575 | throw new IllegalStateException();
576 | }
577 | expectedModCount = modCount;
578 | }
579 | }
580 |
581 | public int size() {
582 | return size;
583 | }
584 |
585 | /**
586 | * Removes all of the elements from this priority queue.
587 | * The queue will be empty after this call returns.
588 | */
589 | public void clear() {
590 | modCount++;
591 | for (int i = 0; i < size; i++)
592 | queue[i] = null;
593 | size = 0;
594 | }
595 |
596 | @SuppressWarnings("unchecked")
597 | public E poll() {
598 | if (size == 0)
599 | return null;
600 | int s = --size;
601 | modCount++;
602 | E result = (E) queue[0];
603 | E x = (E) queue[s];
604 | queue[s] = null;
605 | if (s != 0)
606 | siftDown(0, x);
607 | return result;
608 | }
609 |
610 | /**
611 | * Removes the ith element from queue.
612 | *
613 | * Normally this method leaves the elements at up to i-1,
614 | * inclusive, untouched. Under these circumstances, it returns
615 | * null. Occasionally, in order to maintain the heap invariant,
616 | * it must swap a later element of the list with one earlier than
617 | * i. Under these circumstances, this method returns the element
618 | * that was previously at the end of the list and is now at some
619 | * position before i. This fact is used by iterator.remove so as to
620 | * avoid missing traversing elements.
621 | */
622 | @SuppressWarnings("unchecked")
623 | private E removeAt(int i) {
624 | // assert i >= 0 && i < size;
625 | modCount++;
626 | int s = --size;
627 | if (s == i) // removed last element
628 | queue[i] = null;
629 | else {
630 | E moved = (E) queue[s];
631 | queue[s] = null;
632 | siftDown(i, moved);
633 | if (queue[i] == moved) {
634 | siftUp(i, moved);
635 | if (queue[i] != moved)
636 | return moved;
637 | }
638 | }
639 | return null;
640 | }
641 |
642 | /**
643 | * Inserts item x at position k, maintaining heap invariant by
644 | * promoting x up the tree until it is greater than or equal to
645 | * its parent, or is the root.
646 | *
647 | * To simplify and speed up coercions and comparisons. the
648 | * Comparable and Comparator versions are separated into different
649 | * methods that are otherwise identical. (Similarly for siftDown.)
650 | *
651 | * @param k the position to fill
652 | * @param x the item to insert
653 | */
654 | private void siftUp(int k, E x) {
655 | if (comparator != null)
656 | siftUpUsingComparator(k, x);
657 | else
658 | siftUpComparable(k, x);
659 | }
660 |
661 | @SuppressWarnings("unchecked")
662 | private void siftUpComparable(int k, E x) {
663 | Comparable super E> key = (Comparable super E>) x;
664 | while (k > 0) {
665 | int parent = (k - 1) >>> 1;
666 | Object e = queue[parent];
667 | if (key.compareTo((E) e) >= 0)
668 | break;
669 | queue[k] = e;
670 | k = parent;
671 | }
672 | queue[k] = key;
673 | }
674 |
675 | @SuppressWarnings("unchecked")
676 | private void siftUpUsingComparator(int k, E x) {
677 | while (k > 0) {
678 | int parent = (k - 1) >>> 1;
679 | Object e = queue[parent];
680 | if (comparator.compare(x, (E) e) >= 0)
681 | break;
682 | queue[k] = e;
683 | k = parent;
684 | }
685 | queue[k] = x;
686 | }
687 |
688 | /**
689 | * Inserts item x at position k, maintaining heap invariant by
690 | * demoting x down the tree repeatedly until it is less than or
691 | * equal to its children or is a leaf.
692 | *
693 | * @param k the position to fill
694 | * @param x the item to insert
695 | */
696 | private void siftDown(int k, E x) {
697 | if (comparator != null)
698 | siftDownUsingComparator(k, x);
699 | else
700 | siftDownComparable(k, x);
701 | }
702 |
703 | @SuppressWarnings("unchecked")
704 | private void siftDownComparable(int k, E x) {
705 | Comparable super E> key = (Comparable super E>)x;
706 | int half = size >>> 1; // loop while a non-leaf
707 | while (k < half) {
708 | int child = (k << 1) + 1; // assume left child is least
709 | Object c = queue[child];
710 | int right = child + 1;
711 | if (right < size &&
712 | ((Comparable super E>) c).compareTo((E) queue[right]) > 0)
713 | c = queue[child = right];
714 | if (key.compareTo((E) c) <= 0)
715 | break;
716 | queue[k] = c;
717 | k = child;
718 | }
719 | queue[k] = key;
720 | }
721 |
722 | @SuppressWarnings("unchecked")
723 | private void siftDownUsingComparator(int k, E x) {
724 | int half = size >>> 1;
725 | while (k < half) {
726 | int child = (k << 1) + 1;
727 | Object c = queue[child];
728 | int right = child + 1;
729 | if (right < size &&
730 | comparator.compare((E) c, (E) queue[right]) > 0)
731 | c = queue[child = right];
732 | if (comparator.compare(x, (E) c) <= 0)
733 | break;
734 | queue[k] = c;
735 | k = child;
736 | }
737 | queue[k] = x;
738 | }
739 |
740 | /**
741 | * Establishes the heap invariant (described above) in the entire tree,
742 | * assuming nothing about the order of the elements prior to the call.
743 | */
744 | @SuppressWarnings("unchecked")
745 | private void heapify() {
746 | for (int i = (size >>> 1) - 1; i >= 0; i--)
747 | siftDown(i, (E) queue[i]);
748 | }
749 |
750 | /**
751 | * Returns the comparator used to order the elements in this
752 | * queue, or {@code null} if this queue is sorted according to
753 | * the {@linkplain Comparable natural ordering} of its elements.
754 | *
755 | * @return the comparator used to order this queue, or
756 | * {@code null} if this queue is sorted according to the
757 | * natural ordering of its elements
758 | */
759 | public Comparator super E> comparator() {
760 | return comparator;
761 | }
762 |
763 | /**
764 | * Saves this queue to a stream (that is, serializes it).
765 | *
766 | * @serialData The length of the array backing the instance is
767 | * emitted (int), followed by all of its elements
768 | * (each an {@code Object}) in the proper order.
769 | * @param s the stream
770 | */
771 | private void writeObject(java.io.ObjectOutputStream s)
772 | throws java.io.IOException {
773 | // Write out element count, and any hidden stuff
774 | s.defaultWriteObject();
775 |
776 | // Write out array length, for compatibility with 1.5 version
777 | s.writeInt(Math.max(2, size + 1));
778 |
779 | // Write out all elements in the "proper order".
780 | for (int i = 0; i < size; i++)
781 | s.writeObject(queue[i]);
782 | }
783 |
784 | /**
785 | * Reconstitutes the {@code PriorityQueue} instance from a stream
786 | * (that is, deserializes it).
787 | *
788 | * @param s the stream
789 | */
790 | private void readObject(java.io.ObjectInputStream s)
791 | throws java.io.IOException, ClassNotFoundException {
792 | // Read in size, and any hidden stuff
793 | s.defaultReadObject();
794 |
795 | // Read in (and discard) array length
796 | s.readInt();
797 |
798 | queue = new Object[size];
799 |
800 | // Read in all elements.
801 | for (int i = 0; i < size; i++)
802 | queue[i] = s.readObject();
803 |
804 | // Elements are guaranteed to be in "proper order", but the
805 | // spec has never explained what that might be.
806 | heapify();
807 | }
808 |
809 | /**
810 | * Creates a late-binding
811 | * and fail-fast {@link Spliterator} over the elements in this
812 | * queue.
813 | *
814 | * The {@code Spliterator} reports {@link Spliterator#SIZED},
815 | * {@link Spliterator#SUBSIZED}, and {@link Spliterator#NONNULL}.
816 | * Overriding implementations should document the reporting of additional
817 | * characteristic values.
818 | *
819 | * @return a {@code Spliterator} over the elements in this queue
820 | * @since 1.8
821 | */
822 | public final Spliterator spliterator() {
823 | return new PriorityQueueSpliterator(this, 0, -1, 0);
824 | }
825 |
826 | static final class PriorityQueueSpliterator implements Spliterator {
827 | /*
828 | * This is very similar to ArrayList Spliterator, except for
829 | * extra null checks.
830 | */
831 | private final PriorityQueue pq;
832 | private int index; // current index, modified on advance/split
833 | private int fence; // -1 until first use
834 | private int expectedModCount; // initialized when fence set
835 |
836 | /** Creates new spliterator covering the given range */
837 | PriorityQueueSpliterator(PriorityQueue pq, int origin, int fence,
838 | int expectedModCount) {
839 | this.pq = pq;
840 | this.index = origin;
841 | this.fence = fence;
842 | this.expectedModCount = expectedModCount;
843 | }
844 |
845 | private int getFence() { // initialize fence to size on first use
846 | int hi;
847 | if ((hi = fence) < 0) {
848 | expectedModCount = pq.modCount;
849 | hi = fence = pq.size;
850 | }
851 | return hi;
852 | }
853 |
854 | public PriorityQueueSpliterator trySplit() {
855 | int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
856 | return (lo >= mid) ? null :
857 | new PriorityQueueSpliterator(pq, lo, index = mid,
858 | expectedModCount);
859 | }
860 |
861 | @SuppressWarnings("unchecked")
862 | public void forEachRemaining(Consumer super E> action) {
863 | int i, hi, mc; // hoist accesses and checks from loop
864 | PriorityQueue q; Object[] a;
865 | if (action == null)
866 | throw new NullPointerException();
867 | if ((q = pq) != null && (a = q.queue) != null) {
868 | if ((hi = fence) < 0) {
869 | mc = q.modCount;
870 | hi = q.size;
871 | }
872 | else
873 | mc = expectedModCount;
874 | if ((i = index) >= 0 && (index = hi) <= a.length) {
875 | for (E e;; ++i) {
876 | if (i < hi) {
877 | if ((e = (E) a[i]) == null) // must be CME
878 | break;
879 | action.accept(e);
880 | }
881 | else if (q.modCount != mc)
882 | break;
883 | else
884 | return;
885 | }
886 | }
887 | }
888 | throw new ConcurrentModificationException();
889 | }
890 |
891 | public boolean tryAdvance(Consumer super E> action) {
892 | if (action == null)
893 | throw new NullPointerException();
894 | int hi = getFence(), lo = index;
895 | if (lo >= 0 && lo < hi) {
896 | index = lo + 1;
897 | @SuppressWarnings("unchecked") E e = (E)pq.queue[lo];
898 | if (e == null)
899 | throw new ConcurrentModificationException();
900 | action.accept(e);
901 | if (pq.modCount != expectedModCount)
902 | throw new ConcurrentModificationException();
903 | return true;
904 | }
905 | return false;
906 | }
907 |
908 | public long estimateSize() {
909 | return (long) (getFence() - index);
910 | }
911 |
912 | public int characteristics() {
913 | return Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.NONNULL;
914 | }
915 | }
916 | }
917 |
--------------------------------------------------------------------------------
/src/main/java/android/os/utils/Logger.java:
--------------------------------------------------------------------------------
1 | package android.os.utils;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.Date;
5 |
6 | public class Logger {
7 | private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
8 |
9 | private static final boolean DEBUG;
10 |
11 | static {
12 | boolean isDebug = false;
13 | try {
14 | isDebug = Logger.class.getClassLoader().getResource("logger/debug") != null;
15 | } catch (Exception e) {
16 | e.printStackTrace();
17 | }
18 | DEBUG = isDebug;
19 | }
20 |
21 | public static void debug(Object msg, Object ... args){
22 | if(DEBUG){
23 | StackTraceElement ste = new Throwable().getStackTrace()[1];
24 | StringBuilder sb = new StringBuilder();
25 | sb.append(SIMPLE_DATE_FORMAT.format(new Date())).append(" [").append(Thread.currentThread().getName()).append("] ")
26 | .append(build(String.format(String.valueOf(msg), args),ste));
27 | System.out.println(sb);
28 | }
29 | }
30 |
31 | private static String build(String log, StackTraceElement ste) {
32 | StringBuilder buf = new StringBuilder();
33 | if (ste.isNativeMethod()) {
34 | buf.append("(Native Method)");
35 | } else {
36 | String fName = ste.getFileName();
37 |
38 | if (fName == null) {
39 | buf.append("(Unknown Source)");
40 | } else {
41 | int lineNum = ste.getLineNumber();
42 | buf.append('(');
43 | buf.append(fName);
44 | if (lineNum >= 0) {
45 | buf.append(':');
46 | buf.append(lineNum);
47 | }
48 | buf.append("):");
49 | }
50 | }
51 | buf.append(log);
52 | return buf.toString();
53 | }
54 |
55 | public static void main(String... args) {
56 | debug("Output nothing.");
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/test/java/android/os/BaseTestHandler.kt:
--------------------------------------------------------------------------------
1 | package android.os
2 |
3 | import android.os.utils.*
4 |
5 | class BaseTestHandler(looper: Looper = Looper.myLooper()) : Handler(looper) {
6 | override fun handleMessage(msg: Message) {
7 | super.handleMessage(msg)
8 | Logger.debug(msg)
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/android/os/HandlerTest.kt:
--------------------------------------------------------------------------------
1 | package android.os
2 |
3 | import android.os.utils.*
4 | import org.junit.*
5 |
6 | class HandlerTest {
7 | private lateinit var looper: Looper
8 |
9 | @Test
10 | fun test() {
11 | Looper.prepare()
12 | looper = Looper.myLooper()
13 |
14 | val workingThread = Thread(Runnable {
15 | testRemove()
16 | looper.quitSafely()
17 | }, "Working-Thread")
18 | workingThread.start()
19 |
20 | Looper.loop()
21 | }
22 |
23 | fun testRemove() {
24 | val token = Any()
25 | val r = Runnable {
26 | Logger.debug("Runnable called!")
27 | }
28 | val handler = BaseTestHandler(looper)
29 |
30 | val msg = Message().also {
31 | it.obj = token
32 | it.who = "msg"
33 | }
34 |
35 | val msg1= Message().also {
36 | it.what = 1
37 | it.who = "msg1"
38 | }
39 |
40 | val msg2 = Message().also {
41 | it.callback = r
42 | it.who = "msg2"
43 | }
44 |
45 | val msg3 = Message().also {
46 | it.callback = r
47 | it.obj = token
48 | it.who = "msg3"
49 | }
50 |
51 | val msg4= Message().also {
52 | it.what = 1
53 | it.obj = token
54 | it.who = "msg4"
55 | }
56 |
57 | handler.sendMessage(msg)
58 | handler.sendMessage(msg1)
59 | handler.sendMessage(msg2)
60 | handler.sendMessageDelayed(msg3, 10)
61 | handler.sendMessageDelayed(msg4, 100)
62 | //handler.removeMessages(1)
63 | //handler.removeCallbacksAndMessages(token)
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/test/resources/logger/debug:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bennyhuo/PortableAndroidHandler/5ea4a596e7d51fcf3219e27af0e3dfd58243357e/src/test/resources/logger/debug
--------------------------------------------------------------------------------