public Iterable<L> bulkGet(Iterable<?> keys) {
    // Initially using the array to store the keys, then reusing it to store the respective L's
    final Object[] array = Iterables.toArray(keys, Object.class);
    if (array.length == 0) {
      return ImmutableList.of();
    }
    int[] stripes = new int[array.length];
    for (int i = 0; i < array.length; i++) {
      stripes[i] = indexFor(array[i]);
    }
    Arrays.sort(stripes);
    // optimize for runs of identical stripes
    int previousStripe = stripes[0];
    array[0] = getAt(previousStripe);
    for (int i = 1; i < array.length; i++) {
      int currentStripe = stripes[i];
      if (currentStripe == previousStripe) {
        array[i] = array[i - 1];
      } else {
        array[i] = getAt(currentStripe);
        previousStripe = currentStripe;
      }
    }
    /*
     * Note that the returned Iterable holds references to the returned stripes, to avoid
     * error-prone code like:
     *
     * Striped<Lock> stripedLock = Striped.lazyWeakXXX(...)'
     * Iterable<Lock> locks = stripedLock.bulkGet(keys);
     * for (Lock lock : locks) {
     *   lock.lock();
     * }
     * operation();
     * for (Lock lock : locks) {
     *   lock.unlock();
     * }
     *
     * If we only held the int[] stripes, translating it on the fly to L's, the original locks
     * might be garbage collected after locking them, ending up in a huge mess.
     */
    @SuppressWarnings("unchecked") // we carefully replaced all keys with their respective L's
    List<L> asList = (List<L>) Arrays.asList(array);
    return Collections.unmodifiableList(asList);
  }
public Iterable < L > bulkGet ( Iterable < ? > keys ) { final Object [ ] array = Iterables . toArray ( keys , Object . class ) ; if ( array . length == 0 ) { return ImmutableList . of ( ) ; } int [ ] stripes = new int [ array . length ] ; for ( int i = 0 ; i < array . length ; i ++ ) { stripes [ i ] = indexFor ( array [ i ] ) ; } Arrays . sort ( stripes ) ; int previousStripe = stripes [ 0 ] ; array [ 0 ] = getAt ( previousStripe ) ; for ( int i = 1 ; i < array . length ; i ++ ) { int currentStripe = stripes [ i ] ; if ( currentStripe == previousStripe ) { array [ i ] = array [ i - 1 ] ; } else { array [ i ] = getAt ( currentStripe ) ; previousStripe = currentStripe ; } } @ SuppressWarnings ( "unchecked" ) List < L > asList = ( List < L > ) Arrays . asList ( array ) ; return Collections . unmodifiableList ( asList ) ; }
Returns the stripes that correspond to the passed objects, in ascending (as per
{@link #getAt(int)}) order. Thus, threads that use the stripes in the order returned
by this method are guaranteed to not deadlock each other.

<p>It should be noted that using a {@code Striped<L>} with relatively few stripes, and
{@code bulkGet(keys)} with a relative large number of keys can cause an excessive number
of shared stripes (much like the birthday paradox, where much fewer than anticipated birthdays
are needed for a pair of them to match). Please consider carefully the implications of the
number of stripes, the intended concurrency level, and the typical number of keys used in a
{@code bulkGet(keys)} operation. See <a href="http://www.mathpages.com/home/kmath199.htm">Balls
in Bins model</a> for mathematical formulas that can be used to estimate the probability of
collisions.

@param keys arbitrary non-null keys
@return the stripes corresponding to the objects (one per each object, derived by delegating
to {@link #get(Object)}; may contain duplicates), in an increasing index order.