/*
* Constellation - An open source and standard compliant SDI
* http://www.constellation-sdi.org
*
* Copyright 2014 Geomatys.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.constellation.concurrent;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* Taken from jacob Hookom's blog at http://weblogs.java.net/blog/jhook/archive/2008/12/accelerating_ap_1.html
*
* Exactly like ExecutorCompletionService, except uses a Semaphore to only permit X tasks to run concurrently
* on the passed Executor.
*/
public class BoundedCompletionService<V> implements CompletionService<V> {
private final Semaphore semaphore;
private final Executor executor;
private final BlockingQueue<Future<V>> completionQueue;
// FutureTask to release Semaphore as completed
private class BoundedFuture extends FutureTask {
BoundedFuture(Callable<V> c) { super(c); }
BoundedFuture(Runnable t, V r) { super(t, r); }
@Override
protected void done() {
semaphore.release();
completionQueue.add(this);
}
}
public BoundedCompletionService(final Executor executor, final int permits) {
this.executor = executor;
this.semaphore = new Semaphore(permits);
this.completionQueue = new LinkedBlockingQueue<Future<V>>();
}
@Override
public Future<V> poll() {
return this.completionQueue.poll();
}
@Override
public Future<V> poll(final long timeout, final TimeUnit unit) throws InterruptedException {
return this.completionQueue.poll(timeout, unit);
}
@Override
public Future<V> submit(final Callable<V> task) {
if (task == null) throw new IllegalArgumentException("task can not be null.");
try {
final BoundedFuture f = new BoundedFuture(task);
this.semaphore.acquire(); // waits
this.executor.execute(f);
return f;
} catch (InterruptedException e) {
// do nothing
}
return null;
}
@Override
public Future<V> submit(final Runnable task, final V result) {
if (task == null) throw new IllegalArgumentException("Task can not be null.");
try {
final BoundedFuture f = new BoundedFuture(task, result);
this.semaphore.acquire(); // waits
this.executor.execute(f);
return f;
} catch (InterruptedException e) {
// do nothing
}
return null;
}
@Override
public Future<V> take() throws InterruptedException {
return this.completionQueue.take();
}
}