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
  /**
   * Remove a value from the bag. This method should only be called with objects obtained by <code>
   * borrow(long, TimeUnit)</code> or <code>reserve(T)</code>
   *
   * @param bagEntry the value to remove
   * @return true if the entry was removed, false otherwise
   * @throws IllegalStateException if an attempt is made to remove an object from the bag that was
   *     not borrowed or reserved first
   */
  public boolean remove(final T bagEntry) {
    if (!bagEntry.compareAndSet(STATE_IN_USE, STATE_REMOVED)
        && !bagEntry.compareAndSet(STATE_RESERVED, STATE_REMOVED)
        && !closed) {
      LOGGER.warn(
          "Attempt to remove an object from the bag that was not borrowed or reserved: {}",
          bagEntry);
      return false;
    }

    final boolean removed = sharedList.remove(bagEntry);
    if (!removed && !closed) {
      LOGGER.warn("Attempt to remove an object from the bag that does not exist: {}", bagEntry);
    }

    // synchronizer.signal();
    return removed;
  }
Example #4
0
 /**
  * The method is used to make an item in the bag "unavailable" for borrowing. It is primarily used
  * when wanting to operate on items returned by the <code>values(int)</code> method. Items that
  * are reserved can be removed from the bag via <code>remove(T)</code> without the need to
  * unreserve them. Items that are not removed from the bag can be make available for borrowing
  * again by calling the <code>unreserve(T)</code> method.
  *
  * @param bagEntry the item to reserve
  * @return true if the item was able to be reserved, false otherwise
  */
 public boolean reserve(final T bagEntry) {
   return bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_RESERVED);
 }