|
1 /* |
|
2 * ==================================================================== |
|
3 * |
|
4 * Licensed to the Apache Software Foundation (ASF) under one or more |
|
5 * contributor license agreements. See the NOTICE file distributed with |
|
6 * this work for additional information regarding copyright ownership. |
|
7 * The ASF licenses this file to You under the Apache License, Version 2.0 |
|
8 * (the "License"); you may not use this file except in compliance with |
|
9 * the License. You may obtain a copy of the License at |
|
10 * |
|
11 * http://www.apache.org/licenses/LICENSE-2.0 |
|
12 * |
|
13 * Unless required by applicable law or agreed to in writing, software |
|
14 * distributed under the License is distributed on an "AS IS" BASIS, |
|
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
16 * See the License for the specific language governing permissions and |
|
17 * limitations under the License. |
|
18 * ==================================================================== |
|
19 * |
|
20 * This software consists of voluntary contributions made by many |
|
21 * individuals on behalf of the Apache Software Foundation. For more |
|
22 * information on the Apache Software Foundation, please see |
|
23 * <http://www.apache.org/>. |
|
24 * |
|
25 */ |
|
26 |
|
27 package ch.boye.httpclientandroidlib.impl.conn.tsccm; |
|
28 |
|
29 |
|
30 import java.util.Date; |
|
31 import java.util.concurrent.locks.Condition; |
|
32 |
|
33 import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; |
|
34 |
|
35 /** |
|
36 * Represents a thread waiting for a connection. |
|
37 * This class implements throwaway objects. It is instantiated whenever |
|
38 * a thread needs to wait. Instances are not re-used, except if the |
|
39 * waiting thread experiences a spurious wakeup and continues to wait. |
|
40 * <br/> |
|
41 * All methods assume external synchronization on the condition |
|
42 * passed to the constructor. |
|
43 * Instances of this class do <i>not</i> synchronize access! |
|
44 * |
|
45 * |
|
46 * @since 4.0 |
|
47 */ |
|
48 @NotThreadSafe |
|
49 public class WaitingThread { |
|
50 |
|
51 /** The condition on which the thread is waiting. */ |
|
52 private final Condition cond; |
|
53 |
|
54 /** The route specific pool on which the thread is waiting. */ |
|
55 //@@@ replace with generic pool interface |
|
56 private final RouteSpecificPool pool; |
|
57 |
|
58 /** The thread that is waiting for an entry. */ |
|
59 private Thread waiter; |
|
60 |
|
61 /** True if this was interrupted. */ |
|
62 private boolean aborted; |
|
63 |
|
64 |
|
65 /** |
|
66 * Creates a new entry for a waiting thread. |
|
67 * |
|
68 * @param cond the condition for which to wait |
|
69 * @param pool the pool on which the thread will be waiting, |
|
70 * or <code>null</code> |
|
71 */ |
|
72 public WaitingThread(Condition cond, RouteSpecificPool pool) { |
|
73 |
|
74 if (cond == null) { |
|
75 throw new IllegalArgumentException("Condition must not be null."); |
|
76 } |
|
77 |
|
78 this.cond = cond; |
|
79 this.pool = pool; |
|
80 } |
|
81 |
|
82 |
|
83 /** |
|
84 * Obtains the condition. |
|
85 * |
|
86 * @return the condition on which to wait, never <code>null</code> |
|
87 */ |
|
88 public final Condition getCondition() { |
|
89 // not synchronized |
|
90 return this.cond; |
|
91 } |
|
92 |
|
93 |
|
94 /** |
|
95 * Obtains the pool, if there is one. |
|
96 * |
|
97 * @return the pool on which a thread is or was waiting, |
|
98 * or <code>null</code> |
|
99 */ |
|
100 public final RouteSpecificPool getPool() { |
|
101 // not synchronized |
|
102 return this.pool; |
|
103 } |
|
104 |
|
105 |
|
106 /** |
|
107 * Obtains the thread, if there is one. |
|
108 * |
|
109 * @return the thread which is waiting, or <code>null</code> |
|
110 */ |
|
111 public final Thread getThread() { |
|
112 // not synchronized |
|
113 return this.waiter; |
|
114 } |
|
115 |
|
116 |
|
117 /** |
|
118 * Blocks the calling thread. |
|
119 * This method returns when the thread is notified or interrupted, |
|
120 * if a timeout occurrs, or if there is a spurious wakeup. |
|
121 * <br/> |
|
122 * This method assumes external synchronization. |
|
123 * |
|
124 * @param deadline when to time out, or <code>null</code> for no timeout |
|
125 * |
|
126 * @return <code>true</code> if the condition was satisfied, |
|
127 * <code>false</code> in case of a timeout. |
|
128 * Typically, a call to {@link #wakeup} is used to indicate |
|
129 * that the condition was satisfied. Since the condition is |
|
130 * accessible outside, this cannot be guaranteed though. |
|
131 * |
|
132 * @throws InterruptedException if the waiting thread was interrupted |
|
133 * |
|
134 * @see #wakeup |
|
135 */ |
|
136 public boolean await(Date deadline) |
|
137 throws InterruptedException { |
|
138 |
|
139 // This is only a sanity check. We cannot synchronize here, |
|
140 // the lock would not be released on calling cond.await() below. |
|
141 if (this.waiter != null) { |
|
142 throw new IllegalStateException |
|
143 ("A thread is already waiting on this object." + |
|
144 "\ncaller: " + Thread.currentThread() + |
|
145 "\nwaiter: " + this.waiter); |
|
146 } |
|
147 |
|
148 if (aborted) |
|
149 throw new InterruptedException("Operation interrupted"); |
|
150 |
|
151 this.waiter = Thread.currentThread(); |
|
152 |
|
153 boolean success = false; |
|
154 try { |
|
155 if (deadline != null) { |
|
156 success = this.cond.awaitUntil(deadline); |
|
157 } else { |
|
158 this.cond.await(); |
|
159 success = true; |
|
160 } |
|
161 if (aborted) |
|
162 throw new InterruptedException("Operation interrupted"); |
|
163 } finally { |
|
164 this.waiter = null; |
|
165 } |
|
166 return success; |
|
167 |
|
168 } // await |
|
169 |
|
170 |
|
171 /** |
|
172 * Wakes up the waiting thread. |
|
173 * <br/> |
|
174 * This method assumes external synchronization. |
|
175 */ |
|
176 public void wakeup() { |
|
177 |
|
178 // If external synchronization and pooling works properly, |
|
179 // this cannot happen. Just a sanity check. |
|
180 if (this.waiter == null) { |
|
181 throw new IllegalStateException |
|
182 ("Nobody waiting on this object."); |
|
183 } |
|
184 |
|
185 // One condition might be shared by several WaitingThread instances. |
|
186 // It probably isn't, but just in case: wake all, not just one. |
|
187 this.cond.signalAll(); |
|
188 } |
|
189 |
|
190 public void interrupt() { |
|
191 aborted = true; |
|
192 this.cond.signalAll(); |
|
193 } |
|
194 |
|
195 |
|
196 } // class WaitingThread |