package org.rr.commons.utils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.rr.commons.collection.IteratorList;
public class ThreadUtils {
private static final Object MUTEX = new Object();
public static <S,T> List<T> loopAndWait(final Iterable<S> l, final RunnableImpl<S,T> each, final int maxThreads) {
return loopAndWait(l.iterator(), each, maxThreads);
}
public static <S,T> List<T> loopAndWait(final Iterator<S> l, final RunnableImpl<S,T> each, final int maxThreads) {
return loopAndWait(new IteratorList<S>(l, -1), each, maxThreads);
}
public static <S,T> List<T> loopAndWait(final List<S> l, final RunnableImpl<S,T> each, int maxThreads) {
return loop(l, each, maxThreads, true);
}
/**
* Does a loop over the given list where the <code>each</code> parameter is
* invoked with any entry in the list. The
*
* @param l The list to be looped.
* @param each The {@link RunnableImpl} implementation which is executed with each list entry.
* @param maxThreads Maximum number of Threads to be executed to run the {@link RunnableImpl} implementations.
* @return A list of results for each RunnableImpl in the same order than given with <code>each</code>.
*/
private static <S, T> List<T> loop(final List<S> l, final RunnableImpl<S, T> each, int maxThreads, boolean wait) {
final Thread[] slots = new Thread[maxThreads];
final List<T> results = Collections.synchronizedList(l != null ? new ArrayList<T>(l.size()) : Collections.<T>emptyList());
final List<S> working = Collections.synchronizedList(l != null ? new ArrayList<S>(l) : Collections.<S>emptyList());
while(!working.isEmpty()) {
//thread slot searching and execution must be synchronized.
synchronized(MUTEX) {
boolean emptySlotFound = false;
for(int i = 0; i < slots.length; i++) {
final int slot = i;
if(slots[slot] == null) {
//free slot to use.
slots[slot] = new Thread(new Runnable() {
@Override
public void run() {
S entry = null;
try {
entry = working.remove(0);
} catch(IndexOutOfBoundsException e) {
}
if(entry != null) {
int index = l.indexOf(entry);
ListUtils.set(results, each.run(entry), index);
}
slots[slot] = null;
}
});
slots[slot].start();
emptySlotFound = true;
} else {
//no free slot
emptySlotFound = false;
}
}
if(!emptySlotFound && !working.isEmpty()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
}
if(wait) {
while(!containsOnlyNull(slots)) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
return results;
}
private static boolean containsOnlyNull(Object[] values) {
for (int i = 0; i < values.length; i++) {
if(values[i] != null) {
return false;
}
}
return true;
}
public static abstract class RunnableImpl<S, T> {
public abstract T run(S entry);
}
}