001
002 /*
003 * Copyright (C) 2011 Archie L. Cobbs. All rights reserved.
004 *
005 * $Id: ThreadParkingLot.java 104 2011-05-12 18:03:42Z archie.cobbs $
006 */
007
008 package org.dellroad.stuff.java;
009
010 import java.util.HashSet;
011
012 /**
013 * A place for threads to be parked and unparked.
014 *
015 * @since 1.0.102
016 */
017 public class ThreadParkingLot {
018
019 private final HashSet<Thread> parkedThreads = new HashSet<Thread>();
020
021 /**
022 * Park the current thread on this instance. Execution will halt until {@link #unpark unpark()} is invoked
023 * by some other thread with the current thread as the parameter, the given non-zero timeout expires, or
024 * the current thread is interrupted.
025 *
026 * @param timeout maximum time to stay parked, or zero to park indefinitely
027 * @return {@code true} if the thread was unparked by another thread, {@code false} if the timeout expired
028 * @throws IllegalArgumentException if {@code timeout} is negative
029 * @throws InterruptedException if the current thread is interrupted
030 */
031 public synchronized boolean park(long timeout) throws InterruptedException {
032 final Thread thread = Thread.currentThread();
033 this.parkedThreads.add(thread);
034 try {
035 return TimedWait.wait(this, timeout, new Predicate() {
036 @Override
037 public boolean test() {
038 return !ThreadParkingLot.this.parkedThreads.contains(thread);
039 }
040 });
041 } finally {
042 this.parkedThreads.remove(thread);
043 }
044 }
045
046 /**
047 * Unpark a thread.
048 *
049 * @param thread the thread to unpark
050 * @return {@code true} if {@code thread} was successfully unparked, {@code false} if {@code thread}
051 * is not parked on this instance
052 */
053 public synchronized boolean unpark(Thread thread) {
054 boolean wasParked = this.parkedThreads.remove(thread);
055 if (wasParked)
056 this.notifyAll();
057 return wasParked;
058 }
059
060 /**
061 * Determine if the given thread is currently parked on this instance.
062 *
063 * @param thread the thread in question
064 * @return {@code true} if {@code thread} is currently parked on this instance, {@code false} otherwise
065 */
066 public synchronized boolean isParked(Thread thread) {
067 return this.parkedThreads.contains(thread);
068 }
069 }
070