package com.codeaffine.extras.test.util;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConcurrentHelper {
public static Thread startThread( Runnable runnable ) throws InterruptedException {
RunnableWrapper runnableWrapper = new RunnableWrapper( runnable );
Thread result = startDaemonThread( runnableWrapper );
runnableWrapper.awaitRunning();
return result;
}
public static void runInThread( Runnable runnable ) {
AtomicReference<Throwable> exception = new AtomicReference<Throwable>();
Runnable exceptionGuard = new Runnable() {
@Override
public void run() {
try {
runnable.run();
} catch( Throwable thr ) {
exception.set( thr );
}
}
};
run( exceptionGuard );
if( exception.get() != null ) {
throw new RuntimeException( "Caught exception in thread", exception.get() );
}
}
private static void run( Runnable runnable ) {
Thread thread = startDaemonThread( runnable );
try {
thread.join();
} catch( InterruptedException ie ) {
throw new RuntimeException( ie );
}
}
private static Thread startDaemonThread( Runnable runnable ) {
Thread result = new Thread( runnable );
result.setDaemon( true );
result.start();
return result;
}
private ConcurrentHelper() {}
private static class RunnableWrapper implements Runnable {
private final Runnable runnable;
private final Lock lock;
private final Condition running;
RunnableWrapper( Runnable runnable ) {
this.runnable = runnable;
lock = new ReentrantLock();
running = lock.newCondition();
}
@Override
public void run() {
signalRunning();
runnable.run();
}
void awaitRunning() throws InterruptedException {
lock.lock();
try {
running.await();
} finally {
lock.unlock();
}
}
private void signalRunning() {
lock.lock();
try {
running.signal();
} finally {
lock.unlock();
}
}
}
}