/jetty-util/src/main/java/org/eclipse/jetty/util/ConcurrentArrayBlockingQueue.java

https://bitbucket.org/beginnerjyh/jetty.project · Java · 418 lines · 335 code · 48 blank · 35 comment · 43 complexity · 63a6d700ebe2edbaf3b83ae2ecb1fd04 MD5 · raw file

  1. //
  2. // ========================================================================
  3. // Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
  4. // ------------------------------------------------------------------------
  5. // All rights reserved. This program and the accompanying materials
  6. // are made available under the terms of the Eclipse Public License v1.0
  7. // and Apache License v2.0 which accompanies this distribution.
  8. //
  9. // The Eclipse Public License is available at
  10. // http://www.eclipse.org/legal/epl-v10.html
  11. //
  12. // The Apache License v2.0 is available at
  13. // http://www.opensource.org/licenses/apache2.0.php
  14. //
  15. // You may elect to redistribute this code under either of these licenses.
  16. // ========================================================================
  17. //
  18. package org.eclipse.jetty.util;
  19. import java.util.Collection;
  20. import java.util.Objects;
  21. import java.util.concurrent.BlockingQueue;
  22. import java.util.concurrent.TimeUnit;
  23. import java.util.concurrent.atomic.AtomicInteger;
  24. import java.util.concurrent.atomic.AtomicLongArray;
  25. import java.util.concurrent.locks.Condition;
  26. import java.util.concurrent.locks.Lock;
  27. import java.util.concurrent.locks.ReentrantLock;
  28. /**
  29. * Common functionality for a blocking version of {@link ConcurrentArrayQueue}.
  30. *
  31. * @see Unbounded
  32. * @see Bounded
  33. * @param <E>
  34. */
  35. public abstract class ConcurrentArrayBlockingQueue<E> extends ConcurrentArrayQueue<E> implements BlockingQueue<E>
  36. {
  37. private final Lock _lock = new ReentrantLock();
  38. private final Condition _consumer = _lock.newCondition();
  39. public ConcurrentArrayBlockingQueue(int blockSize)
  40. {
  41. super(blockSize);
  42. }
  43. @Override
  44. public E poll()
  45. {
  46. E result = super.poll();
  47. if (result != null && decrementAndGetSize() > 0)
  48. signalConsumer();
  49. return result;
  50. }
  51. @Override
  52. public boolean remove(Object o)
  53. {
  54. boolean result = super.remove(o);
  55. if (result && decrementAndGetSize() > 0)
  56. signalConsumer();
  57. return result;
  58. }
  59. protected abstract int decrementAndGetSize();
  60. protected void signalConsumer()
  61. {
  62. final Lock lock = _lock;
  63. lock.lock();
  64. try
  65. {
  66. _consumer.signal();
  67. }
  68. finally
  69. {
  70. lock.unlock();
  71. }
  72. }
  73. @Override
  74. public E take() throws InterruptedException
  75. {
  76. while (true)
  77. {
  78. E result = poll();
  79. if (result != null)
  80. return result;
  81. final Lock lock = _lock;
  82. lock.lockInterruptibly();
  83. try
  84. {
  85. if (size() == 0)
  86. {
  87. _consumer.await();
  88. }
  89. }
  90. finally
  91. {
  92. lock.unlock();
  93. }
  94. }
  95. }
  96. @Override
  97. public E poll(long timeout, TimeUnit unit) throws InterruptedException
  98. {
  99. long nanos = unit.toNanos(timeout);
  100. while (true)
  101. {
  102. // TODO should reduce nanos if we spin here
  103. E result = poll();
  104. if (result != null)
  105. return result;
  106. final Lock lock = _lock;
  107. lock.lockInterruptibly();
  108. try
  109. {
  110. if (size() == 0)
  111. {
  112. if (nanos <= 0)
  113. return null;
  114. nanos = _consumer.awaitNanos(nanos);
  115. }
  116. }
  117. finally
  118. {
  119. lock.unlock();
  120. }
  121. }
  122. }
  123. @Override
  124. public int drainTo(Collection<? super E> c)
  125. {
  126. return drainTo(c, Integer.MAX_VALUE);
  127. }
  128. @Override
  129. public int drainTo(Collection<? super E> c, int maxElements)
  130. {
  131. if (c == this)
  132. throw new IllegalArgumentException();
  133. int added = 0;
  134. while (added < maxElements)
  135. {
  136. E element = poll();
  137. if (element == null)
  138. break;
  139. c.add(element);
  140. ++added;
  141. }
  142. return added;
  143. }
  144. /**
  145. * An unbounded, blocking version of {@link ConcurrentArrayQueue}.
  146. *
  147. * @param <E>
  148. */
  149. public static class Unbounded<E> extends ConcurrentArrayBlockingQueue<E>
  150. {
  151. private static final int SIZE_LEFT_OFFSET = MemoryUtils.getLongsPerCacheLine() - 1;
  152. private static final int SIZE_RIGHT_OFFSET = SIZE_LEFT_OFFSET + MemoryUtils.getLongsPerCacheLine();
  153. private final AtomicLongArray _sizes = new AtomicLongArray(SIZE_RIGHT_OFFSET+1);
  154. public Unbounded()
  155. {
  156. this(DEFAULT_BLOCK_SIZE);
  157. }
  158. public Unbounded(int blockSize)
  159. {
  160. super(blockSize);
  161. }
  162. @Override
  163. public boolean offer(E item)
  164. {
  165. boolean result = super.offer(item);
  166. if (result && getAndIncrementSize() == 0)
  167. signalConsumer();
  168. return result;
  169. }
  170. private int getAndIncrementSize()
  171. {
  172. long sizeRight = _sizes.getAndIncrement(SIZE_RIGHT_OFFSET);
  173. long sizeLeft = _sizes.get(SIZE_LEFT_OFFSET);
  174. return (int)(sizeRight - sizeLeft);
  175. }
  176. @Override
  177. protected int decrementAndGetSize()
  178. {
  179. long sizeLeft = _sizes.incrementAndGet(SIZE_LEFT_OFFSET);
  180. long sizeRight = _sizes.get(SIZE_RIGHT_OFFSET);
  181. return (int)(sizeRight - sizeLeft);
  182. }
  183. @Override
  184. public int size()
  185. {
  186. long sizeLeft = _sizes.get(SIZE_LEFT_OFFSET);
  187. long sizeRight = _sizes.get(SIZE_RIGHT_OFFSET);
  188. return (int)(sizeRight - sizeLeft);
  189. }
  190. @Override
  191. public int remainingCapacity()
  192. {
  193. return Integer.MAX_VALUE;
  194. }
  195. @Override
  196. public void put(E element) throws InterruptedException
  197. {
  198. offer(element);
  199. }
  200. @Override
  201. public boolean offer(E element, long timeout, TimeUnit unit) throws InterruptedException
  202. {
  203. return offer(element);
  204. }
  205. }
  206. /**
  207. * A bounded, blocking version of {@link ConcurrentArrayQueue}.
  208. *
  209. * @param <E>
  210. */
  211. public static class Bounded<E> extends ConcurrentArrayBlockingQueue<E>
  212. {
  213. private final AtomicInteger _size = new AtomicInteger();
  214. private final Lock _lock = new ReentrantLock();
  215. private final Condition _producer = _lock.newCondition();
  216. private final int _capacity;
  217. public Bounded(int capacity)
  218. {
  219. this(DEFAULT_BLOCK_SIZE, capacity);
  220. }
  221. public Bounded(int blockSize, int capacity)
  222. {
  223. super(blockSize);
  224. this._capacity = capacity;
  225. }
  226. @Override
  227. public boolean offer(E item)
  228. {
  229. while (true)
  230. {
  231. int size = size();
  232. int nextSize = size + 1;
  233. if (nextSize > _capacity)
  234. return false;
  235. if (_size.compareAndSet(size, nextSize))
  236. {
  237. if (super.offer(item))
  238. {
  239. if (size == 0)
  240. signalConsumer();
  241. return true;
  242. }
  243. else
  244. {
  245. decrementAndGetSize();
  246. }
  247. }
  248. }
  249. }
  250. @Override
  251. public E poll()
  252. {
  253. E result = super.poll();
  254. if (result != null)
  255. signalProducer();
  256. return result;
  257. }
  258. @Override
  259. public boolean remove(Object o)
  260. {
  261. boolean result = super.remove(o);
  262. if (result)
  263. signalProducer();
  264. return result;
  265. }
  266. @Override
  267. protected int decrementAndGetSize()
  268. {
  269. return _size.decrementAndGet();
  270. }
  271. @Override
  272. public int size()
  273. {
  274. return _size.get();
  275. }
  276. @Override
  277. public int remainingCapacity()
  278. {
  279. return _capacity - size();
  280. }
  281. @Override
  282. public void put(E item) throws InterruptedException
  283. {
  284. item = Objects.requireNonNull(item);
  285. while (true)
  286. {
  287. final Lock lock = _lock;
  288. lock.lockInterruptibly();
  289. try
  290. {
  291. if (size() == _capacity)
  292. _producer.await();
  293. }
  294. finally
  295. {
  296. lock.unlock();
  297. }
  298. if (offer(item))
  299. break;
  300. }
  301. }
  302. @Override
  303. public boolean offer(E item, long timeout, TimeUnit unit) throws InterruptedException
  304. {
  305. item = Objects.requireNonNull(item);
  306. long nanos = unit.toNanos(timeout);
  307. while (true)
  308. {
  309. final Lock lock = _lock;
  310. lock.lockInterruptibly();
  311. try
  312. {
  313. if (size() == _capacity)
  314. {
  315. if (nanos <= 0)
  316. return false;
  317. nanos = _producer.awaitNanos(nanos);
  318. }
  319. }
  320. finally
  321. {
  322. lock.unlock();
  323. }
  324. if (offer(item))
  325. break;
  326. }
  327. return true;
  328. }
  329. @Override
  330. public int drainTo(Collection<? super E> c, int maxElements)
  331. {
  332. int result = super.drainTo(c, maxElements);
  333. if (result > 0)
  334. signalProducers();
  335. return result;
  336. }
  337. @Override
  338. public void clear()
  339. {
  340. super.clear();
  341. signalProducers();
  342. }
  343. private void signalProducer()
  344. {
  345. final Lock lock = _lock;
  346. lock.lock();
  347. try
  348. {
  349. _producer.signal();
  350. }
  351. finally
  352. {
  353. lock.unlock();
  354. }
  355. }
  356. private void signalProducers()
  357. {
  358. final Lock lock = _lock;
  359. lock.lock();
  360. try
  361. {
  362. _producer.signalAll();
  363. }
  364. finally
  365. {
  366. lock.unlock();
  367. }
  368. }
  369. }
  370. }