All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
net.sf.hajdbc.util.concurrent.SynchronousExecutor Maven / Gradle / Ivy
/*
* HA-JDBC: High-Availability JDBC
* Copyright (C) 2012 Paul Ferraro
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package net.sf.hajdbc.util.concurrent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import net.sf.hajdbc.util.Reversed;
/**
* Executor service that executes tasks in the caller thread.
*
* @author Paul Ferraro
*/
public class SynchronousExecutor extends AbstractExecutorService
{
private final ExecutorService executor;
private final boolean reverse;
public SynchronousExecutor(ExecutorService executor)
{
this(executor, false);
}
public SynchronousExecutor(ExecutorService executor, boolean reverse)
{
this.executor = executor;
this.reverse = reverse;
}
/**
* @see java.util.concurrent.ExecutorService#awaitTermination(long, java.util.concurrent.TimeUnit)
*/
@Override
public boolean awaitTermination(long time, TimeUnit unit) throws InterruptedException
{
return this.executor.awaitTermination(time, unit);
}
/**
* @see java.util.concurrent.ExecutorService#isShutdown()
*/
@Override
public boolean isShutdown()
{
return this.executor.isShutdown();
}
/**
* @see java.util.concurrent.ExecutorService#isTerminated()
*/
@Override
public boolean isTerminated()
{
return this.executor.isTerminated();
}
/**
* @see java.util.concurrent.ExecutorService#shutdown()
*/
@Override
public void shutdown()
{
this.executor.shutdown();
}
/**
* @see java.util.concurrent.ExecutorService#shutdownNow()
*/
@Override
public List shutdownNow()
{
return this.executor.shutdownNow();
}
/**
* @see java.util.concurrent.Executor#execute(java.lang.Runnable)
*/
@Override
public void execute(Runnable task)
{
task.run();
}
/**
* {@inheritDoc}
* @see java.util.concurrent.AbstractExecutorService#submit(java.lang.Runnable)
*/
@Override
public Future> submit(Runnable task)
{
return this.submit(Executors.callable(task));
}
/**
* {@inheritDoc}
* @see java.util.concurrent.AbstractExecutorService#submit(java.lang.Runnable, java.lang.Object)
*/
@Override
public Future submit(Runnable task, T result)
{
return this.submit(Executors.callable(task, result));
}
/**
* {@inheritDoc}
* @see java.util.concurrent.AbstractExecutorService#submit(java.util.concurrent.Callable)
*/
@Override
public Future submit(Callable task)
{
return new EagerFuture(task);
}
/**
* Executes the specified tasks serially, until the first successful result, then the remainder using the executor with which this executor was created.
* {@inheritDoc}
* @see java.util.concurrent.AbstractExecutorService#invokeAll(java.util.Collection)
*/
@Override
public List> invokeAll(Collection extends Callable> tasks) throws InterruptedException
{
return this.invokeAll(tasks, Long.MAX_VALUE, TimeUnit.MILLISECONDS);
}
/**
* {@inheritDoc}
* @see java.util.concurrent.AbstractExecutorService#invokeAll(java.util.Collection, long, java.util.concurrent.TimeUnit)
*/
@Override
public List> invokeAll(Collection extends Callable> tasks, long timeout, TimeUnit unit) throws InterruptedException
{
if (tasks.isEmpty()) return Collections.emptyList();
long end = (timeout == Long.MAX_VALUE) ? 0 : System.currentTimeMillis() + unit.toMillis(timeout);
boolean synchronous = !this.reverse;
int remaining = tasks.size();
LinkedList> futures = new LinkedList>();
for (Callable task: this.reverse ? new Reversed>(new ArrayList>(tasks)) : tasks)
{
remaining -= 1;
if (synchronous)
{
Future future = this.reverse ? new LazyFuture(task) : new EagerFuture(task);
if (this.reverse)
{
futures.addFirst(future);
}
else
{
futures.addLast(future);
}
// Execute remaining tasks in parallel, if there are multiple
if (remaining > 1)
{
synchronous = false;
}
}
else
{
Future future = this.executor.submit(task);
if (this.reverse)
{
futures.addFirst(future);
}
else
{
futures.addLast(future);
}
if (this.reverse && (remaining == 1))
{
synchronous = true;
}
}
}
try
{
// Wait until all tasks have finished
for (Future future: this.reverse ? new Reversed>(futures) : futures)
{
if (!future.isDone())
{
try
{
if (end == 0)
{
future.get();
}
else
{
long now = System.currentTimeMillis();
if (now < end)
{
future.get(end - now, TimeUnit.MILLISECONDS);
}
}
}
catch (ExecutionException e)
{
// Ignore
}
catch (CancellationException e)
{
// Ignore
}
}
}
}
catch (TimeoutException e)
{
// Ignore
}
finally
{
// If interrupted, cancel any unfinished tasks
for (Future future: this.reverse ? new Reversed>(futures) : futures)
{
if (!future.isDone())
{
future.cancel(true);
}
}
}
return futures;
}
/**
* {@inheritDoc}
* @see java.util.concurrent.AbstractExecutorService#invokeAny(java.util.Collection)
*/
@Override
public T invokeAny(Collection extends Callable> tasks) throws InterruptedException, ExecutionException
{
return this.getAny(this.invokeAll(tasks));
}
/**
* {@inheritDoc}
* @see java.util.concurrent.AbstractExecutorService#invokeAny(java.util.Collection, long, java.util.concurrent.TimeUnit)
*/
@Override
public T invokeAny(Collection extends Callable> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException
{
return this.getAny(this.invokeAll(tasks, timeout, unit));
}
private T getAny(List> futures) throws InterruptedException, ExecutionException
{
if (futures.isEmpty()) throw new IllegalArgumentException();
return futures.get(this.reverse ? (futures.size() - 1) : 0).get();
}
/**
* Future that doesn't execute its task until get(...).
*/
private static class LazyFuture implements Future
{
private enum State
{
NEW, CANCELLED, DONE;
}
private final Callable task;
private volatile T result;
private volatile ExecutionException exception;
private final AtomicReference state = new AtomicReference(State.NEW);
private final CountDownLatch latch = new CountDownLatch(1);
LazyFuture(Callable task)
{
this.task = task;
}
/**
* {@inheritDoc}
* @see java.util.concurrent.Future#cancel(boolean)
*/
@Override
public boolean cancel(boolean interrupt)
{
return this.state.compareAndSet(State.NEW, State.CANCELLED);
}
/**
* {@inheritDoc}
* @see java.util.concurrent.Future#get()
*/
@Override
public T get() throws ExecutionException, InterruptedException
{
return this.get(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
}
/**
* {@inheritDoc}
* @see java.util.concurrent.Future#get(long, java.util.concurrent.TimeUnit)
*/
@Override
public T get(long time, TimeUnit unit) throws ExecutionException, InterruptedException
{
if (this.state.compareAndSet(State.NEW, State.DONE))
{
try
{
this.result = this.task.call();
}
catch (Throwable e)
{
this.exception = new ExecutionException(e);
}
this.latch.countDown();
}
if (this.state.get() == State.CANCELLED)
{
throw new CancellationException();
}
if (time == Long.MAX_VALUE)
{
this.latch.await();
}
else
{
this.latch.await(time, unit);
}
if (this.exception != null)
{
throw this.exception;
}
return this.result;
}
/**
* {@inheritDoc}
* @see java.util.concurrent.Future#isCancelled()
*/
@Override
public boolean isCancelled()
{
return this.state.get() == State.CANCELLED;
}
/**
* {@inheritDoc}
* @see java.util.concurrent.Future#isDone()
*/
@Override
public boolean isDone()
{
return this.state.get() == State.DONE;
}
}
/**
* Light-weight future implementation that executes its task on construction.
* @param
*/
private static class EagerFuture implements Future
{
private T result;
private ExecutionException exception;
EagerFuture(Callable task)
{
try
{
this.result = task.call();
}
catch (Throwable e)
{
this.exception = new ExecutionException(e);
}
}
@Override
public boolean cancel(boolean mayInterruptIfRunning)
{
return false;
}
@Override
public T get() throws ExecutionException
{
if (this.exception != null) throw this.exception;
return this.result;
}
@Override
public T get(long time, TimeUnit unit) throws ExecutionException
{
return this.get();
}
@Override
public boolean isCancelled()
{
return false;
}
@Override
public boolean isDone()
{
return true;
}
}
}