mapの並列処理化

こんなんができた。スレッドプールを使いまわす関係上、staticなメソッドじゃなくなったことが大きな違い。また、各要素に対してFunctionを並列処理で動かすためのCallableインスタンスを作るために1回コレクションを走査し、各要素の計算結果を受け取るためにもう1回コレクションを走査する関係上、計算が軽いコレクションに対しては、あんまり有効じゃないかもしれません。しくしく。
スレッドプールのスレッド数はCPUコア数+2。*2くらいでもよい気がする。


一部省略したものの、ソース。

/**
 * High-order functions for Java collections.
 */
public class CollectionUtil {
	private static CollectionUtil instance;
	private ExecutorService service;

	private CollectionUtil() {
		 service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 2);
	}
	
	public static CollectionUtil getInstance() {
		if (instance == null) {
			synchronized (CollectionUtil.class) {
				if (instance == null) {
					instance = new CollectionUtil();
				}
			}
		}
		return instance;
	}
	
	public static <T0, T1> List<T1> map(Collection<T0> collection, Function<T0, T1> function) {
		List<T1> result = new ArrayList<T1>(collection.size());
		for (T0 element : collection) {
			result.add(function.apply(element));
		}
		return result;
	}
	
	public <T0, T1> List<T1> map2(Collection<T0> collection, Function<T0, T1> function) throws
		InterruptedException, ExecutionException {

		List<Future<T1>> futureList = new ArrayList<Future<T1>>(collection.size());
		//各要素を、スレッドプールに計算させる。
		//ElementRunnerがCallableインタフェースの実装クラスなので、
		//service内のスレッドプールが計算してくれます。
		for (T0 element : collection) {
			futureList.add(service.submit(new ElementRunner(element, function)));
		}

		//各要素の計算結果を取得する。
		List<T1> result = new ArrayList<T1>(collection.size());
		for(Future<T1> element : futureList) {
			result.add(element.get());
		}
		
		return result;
	}
}

class ElementRunner<T0, T1> implements Callable<T1> {
	private T0 t;
	private Function<T0, T1> fn;
	
	public ElementRunner(T0 t, Function<T0, T1> fn) {
		this.t = t;
		this.fn = fn;
	}

	public T1 call() throws Exception {
		return fn.apply(t);
	}
}

ツッコミ歓迎。