io.atomix.catalyst.concurrent.SingleThreadContext Maven / Gradle / Ivy
package io.atomix.catalyst.concurrent;
import io.atomix.catalyst.serializer.Serializer;
import io.atomix.catalyst.util.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Duration;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
/**
* Single threaded context.
*
* This is a basic {@link ThreadContext} implementation that uses a
* {@link java.util.concurrent.ScheduledExecutorService} to schedule events on the context thread.
*
* @author Jordan Halterman
*/
public class SingleThreadContext implements ThreadContext {
private static final Logger LOGGER = LoggerFactory.getLogger(SingleThreadContext.class);
private final ScheduledExecutorService executor;
private final Serializer serializer;
private volatile boolean blocked;
private final Executor wrappedExecutor = new Executor() {
@Override
public void execute(Runnable command) {
try {
executor.execute(Runnables.logFailure(command, LOGGER));
} catch (RejectedExecutionException e) {
}
}
};
/**
* Creates a new single thread context.
*
* The provided context name will be passed to {@link CatalystThreadFactory} and used
* when instantiating the context thread.
*
* @param nameFormat The context nameFormat which will be formatted with a thread number.
* @param serializer The context serializer.
*/
public SingleThreadContext(String nameFormat, Serializer serializer) {
this(new CatalystThreadFactory(nameFormat), serializer);
}
/**
* Creates a new single thread context.
*
* @param factory The thread factory.
* @param serializer The context serializer.
*/
public SingleThreadContext(CatalystThreadFactory factory, Serializer serializer) {
this(new ScheduledThreadPoolExecutor(1, factory), serializer);
}
/**
* Creates a new single thread context.
*
* @param executor The executor on which to schedule events. This must be a single thread scheduled executor.
* @param serializer The context serializer.
*/
public SingleThreadContext(ScheduledExecutorService executor, Serializer serializer) {
this(getThread(executor), executor, serializer);
}
public SingleThreadContext(Thread thread, ScheduledExecutorService executor, Serializer serializer) {
this.executor = executor;
this.serializer = serializer;
Assert.state(thread instanceof CatalystThread, "not a Catalyst thread");
((CatalystThread) thread).setContext(this);
}
/**
* Gets the thread from a single threaded executor service.
*/
protected static CatalystThread getThread(ExecutorService executor) {
final AtomicReference thread = new AtomicReference<>();
try {
executor.submit(() -> {
thread.set((CatalystThread) Thread.currentThread());
}).get();
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException("failed to initialize thread state", e);
}
return thread.get();
}
@Override
public void block() {
this.blocked = true;
}
@Override
public void unblock() {
this.blocked = false;
}
@Override
public boolean isBlocked() {
return blocked;
}
@Override
public Logger logger() {
return LOGGER;
}
@Override
public Serializer serializer() {
return serializer;
}
@Override
public Executor executor() {
return wrappedExecutor;
}
@Override
public Scheduled schedule(Duration delay, Runnable runnable) {
ScheduledFuture> future = executor.schedule(Runnables.logFailure(runnable, LOGGER), delay.toMillis(), TimeUnit.MILLISECONDS);
return () -> future.cancel(false);
}
@Override
public Scheduled schedule(Duration delay, Duration interval, Runnable runnable) {
ScheduledFuture> future = executor.scheduleAtFixedRate(Runnables.logFailure(runnable, LOGGER), delay.toMillis(), interval.toMillis(), TimeUnit.MILLISECONDS);
return () -> future.cancel(false);
}
@Override
public void close() {
executor.shutdownNow();
}
}