Example #1
0
  /**
   * The method will borrow a BagEntry from the bag, blocking for the specified timeout if none are
   * available.
   *
   * @param timeout how long to wait before giving up, in units of unit
   * @param timeUnit a <code>TimeUnit</code> determining how to interpret the timeout parameter
   * @return a borrowed instance from the bag or null if a timeout occurs
   * @throws InterruptedException if interrupted while waiting
   */
  public T borrow(long timeout, final TimeUnit timeUnit) throws InterruptedException {
    // Try the thread-local list first
    List<Object> list = threadList.get();
    if (weakThreadLocals && list == null) {
      list = new ArrayList<>(16);
      threadList.set(list);
    }

    for (int i = list.size() - 1; i >= 0; i--) {
      final Object entry = list.remove(i);
      @SuppressWarnings("unchecked")
      final T bagEntry = weakThreadLocals ? ((WeakReference<T>) entry).get() : (T) entry;
      if (bagEntry != null && bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) {
        return bagEntry;
      }
    }

    // Otherwise, scan the shared list ... for maximum of timeout
    timeout = timeUnit.toNanos(timeout);
    Future<Boolean> addItemFuture = null;
    final long startScan = System.nanoTime();
    final long originTimeout = timeout;
    long startSeq;
    waiters.incrementAndGet();
    try {
      do {
        // scan the shared list
        do {
          startSeq = synchronizer.currentSequence();
          for (T bagEntry : sharedList) {
            if (bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) {
              // if we might have stolen another thread's new connection, restart the add...
              if (waiters.get() > 1 && addItemFuture == null) {
                listener.addBagItem();
              }

              return bagEntry;
            }
          }
        } while (startSeq < synchronizer.currentSequence());

        if (addItemFuture == null || addItemFuture.isDone()) {
          addItemFuture = listener.addBagItem();
        }

        timeout = originTimeout - (System.nanoTime() - startScan);
      } while (timeout > 10_000L && synchronizer.waitUntilSequenceExceeded(startSeq, timeout));
    } finally {
      waiters.decrementAndGet();
    }

    return null;
  }
Example #2
0
 /**
  * This method is used to make an item reserved via <code>reserve(T)</code> available again for
  * borrowing.
  *
  * @param bagEntry the item to unreserve
  */
 public void unreserve(final T bagEntry) {
   if (bagEntry.compareAndSet(STATE_RESERVED, STATE_NOT_IN_USE)) {
     synchronizer.signal();
   } else {
     LOGGER.warn("Attempt to relinquish an object to the bag that was not reserved: {}", bagEntry);
   }
 }
Example #3
0
  /**
   * Add a new object to the bag for others to borrow.
   *
   * @param bagEntry an object to add to the bag
   */
  public void add(final T bagEntry) {
    if (closed) {
      LOGGER.info("ConcurrentBag has been closed, ignoring add()");
      throw new IllegalStateException("ConcurrentBag has been closed, ignoring add()");
    }

    sharedList.add(bagEntry);
    synchronizer.signal();
  }
Example #4
0
  /**
   * This method will return a borrowed object to the bag. Objects that are borrowed from the bag
   * but never "requited" will result in a memory leak.
   *
   * @param bagEntry the value to return to the bag
   * @throws NullPointerException if value is null
   * @throws IllegalStateException if the requited value was not borrowed from the bag
   */
  public void requite(final T bagEntry) {
    bagEntry.lazySet(STATE_NOT_IN_USE);

    final List<Object> threadLocalList = threadList.get();
    if (threadLocalList != null) {
      threadLocalList.add(weakThreadLocals ? new WeakReference<>(bagEntry) : bagEntry);
    }

    synchronizer.signal();
  }
Example #5
0
 /**
  * Get the number of threads pending (waiting) for an item from the bag to become available.
  *
  * @return the number of threads waiting for items from the bag
  */
 public int getPendingQueue() {
   return synchronizer.getQueueLength();
 }