/*
* $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/tsccm/WaitingThread.java $
* $Revision: 649217 $
* $Date: 2008-04-17 11:32:32 -0700 (Thu, 17 Apr 2008) $
*
* ====================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.conn.tsccm;
import java.util.Date;
import java.util.concurrent.locks.Condition;
/**
* Represents a thread waiting for a connection.
* This class implements throwaway objects. It is instantiated whenever
* a thread needs to wait. Instances are not re-used, except if the
* waiting thread experiences a spurious wakeup and continues to wait.
* <br/>
* All methods assume external synchronization on the condition
* passed to the constructor.
* Instances of this class do <i>not</i> synchronize access!
*
* @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
*/
public class WaitingThread {
/** The condition on which the thread is waiting. */
private final Condition cond;
/** The route specific pool on which the thread is waiting. */
//@@@ replace with generic pool interface
private final RouteSpecificPool pool;
/** The thread that is waiting for an entry. */
private Thread waiter;
/** True if this was interrupted. */
private boolean aborted;
/**
* Creates a new entry for a waiting thread.
*
* @param cond the condition for which to wait
* @param pool the pool on which the thread will be waiting,
* or <code>null</code>
*/
public WaitingThread(Condition cond, RouteSpecificPool pool) {
if (cond == null) {
throw new IllegalArgumentException("Condition must not be null.");
}
this.cond = cond;
this.pool = pool;
}
/**
* Obtains the condition.
*
* @return the condition on which to wait, never <code>null</code>
*/
public final Condition getCondition() {
// not synchronized
return this.cond;
}
/**
* Obtains the pool, if there is one.
*
* @return the pool on which a thread is or was waiting,
* or <code>null</code>
*/
public final RouteSpecificPool getPool() {
// not synchronized
return this.pool;
}
/**
* Obtains the thread, if there is one.
*
* @return the thread which is waiting, or <code>null</code>
*/
public final Thread getThread() {
// not synchronized
return this.waiter;
}
/**
* Blocks the calling thread.
* This method returns when the thread is notified or interrupted,
* if a timeout occurrs, or if there is a spurious wakeup.
* <br/>
* This method assumes external synchronization.
*
* @param deadline when to time out, or <code>null</code> for no timeout
*
* @return <code>true</code> if the condition was satisfied,
* <code>false</code> in case of a timeout.
* Typically, a call to {@link #wakeup} is used to indicate
* that the condition was satisfied. Since the condition is
* accessible outside, this cannot be guaranteed though.
*
* @throws InterruptedException if the waiting thread was interrupted
*
* @see #wakeup
*/
public boolean await(Date deadline)
throws InterruptedException {
// This is only a sanity check. We cannot synchronize here,
// the lock would not be released on calling cond.await() below.
if (this.waiter != null) {
throw new IllegalStateException
("A thread is already waiting on this object." +
"\ncaller: " + Thread.currentThread() +
"\nwaiter: " + this.waiter);
}
if (aborted)
throw new InterruptedException("Operation interrupted");
this.waiter = Thread.currentThread();
boolean success = false;
try {
if (deadline != null) {
success = this.cond.awaitUntil(deadline);
} else {
this.cond.await();
success = true;
}
if (aborted)
throw new InterruptedException("Operation interrupted");
} finally {
this.waiter = null;
}
return success;
} // await
/**
* Wakes up the waiting thread.
* <br/>
* This method assumes external synchronization.
*/
public void wakeup() {
// If external synchronization and pooling works properly,
// this cannot happen. Just a sanity check.
if (this.waiter == null) {
throw new IllegalStateException
("Nobody waiting on this object.");
}
// One condition might be shared by several WaitingThread instances.
// It probably isn't, but just in case: wake all, not just one.
this.cond.signalAll();
}
public void interrupt() {
aborted = true;
this.cond.signalAll();
}
} // class WaitingThread
|