com.xqbase.util.Runnables Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xqbase-util-jdk17 Show documentation
Show all versions of xqbase-util-jdk17 Show documentation
Reusable Java components for www.xqbase.com
package com.xqbase.util;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import com.xqbase.util.function.Consumer;
import com.xqbase.util.function.RunnableEx;
import com.xqbase.util.function.SupplierEx;
public class Runnables {
static AtomicInteger threadNum = new AtomicInteger(0);
/**
* @return Number of wrapped and active branch thread
* @see #wrap(Runnable)
*/
public static int getThreadNum() {
return threadNum.get();
}
/**
* Wrap a {@link Runnable} in order to:
*
* - Make the logging suffix in branch thread (callee thread)
* the same as trunk thread (caller thread)
* - Make the logging stack trace in branch thread
* concatenating with trunk thread
* - Count number of branch threads
*
*
* @see Log#suffix
* @see Log#throwable
*/
public static Runnable wrap(final Runnable runnable) {
final String suffix = Log.suffix.get();
// t.getCause() is atop t, see Log.concat() for more details
final Throwable t = new Throwable(Log.throwable.get());
return new Runnable() {
@Override
public void run() {
threadNum.incrementAndGet();
Log.suffix.set(suffix);
Log.throwable.set(t);
try {
runnable.run();
} catch (Error | RuntimeException e) {
Log.e(e);
} finally {
Log.throwable.remove();
Log.suffix.remove();
threadNum.decrementAndGet();
}
}
};
}
/**
* Wrap a {@link Callable}
*
* @see #wrap(Runnable)
*/
public static Callable wrap(final Callable callable) {
final String suffix = Log.suffix.get();
// t.getCause() is atop t, see Log.concat() for more details
final Throwable t = new Throwable(Log.throwable.get());
return new Callable() {
@Override
public V call() throws Exception {
threadNum.incrementAndGet();
Log.suffix.set(suffix);
Log.throwable.set(t);
try {
return callable.call();
} catch (Error e) {
throw new Exception(e);
} finally {
Log.throwable.remove();
Log.suffix.remove();
threadNum.decrementAndGet();
}
}
};
}
@SuppressWarnings("unchecked")
private static U cast(T o) {
return (U) o;
}
public static void retry(final RunnableEx
runnable, Consumer handler, int count, int interval) throws E {
retry(new SupplierEx() {
@Override
public Void get() throws E {
runnable.run();
return null;
}
}, handler, count, interval);
}
public static T retry(SupplierEx supplier,
Consumer handler, int count, int interval) throws E {
for (int i = 0; i < count; i ++) {
try {
return supplier.get();
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw e;
}
handler.accept(Runnables.cast(e));
if (interval > 0) {
Time.sleep(interval);
}
}
}
return supplier.get();
}
private static void awaitTermination(ExecutorService service) {
boolean interrupted = Thread.interrupted();
boolean terminated = false;
while (!terminated) {
try {
terminated = service.awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
interrupted = true;
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
}
/**
* Shutdown and wait for a {@link ExecutorService} like {@link ExecutorService#shutdown()}
* and {@link ExecutorService#awaitTermination(long, TimeUnit)} but ignore interruption
* The interrupted status will not be cleared if current thread is interrupted during shutdown
*/
public static void shutdown(ExecutorService service) {
service.shutdown();
awaitTermination(service);
}
/**
* Shutdown immediately and wait for a {@link ExecutorService} like {@link ExecutorService#shutdownNow()}
* and {@link ExecutorService#awaitTermination(long, TimeUnit)} but ignore interruption
* The interrupted status will not be cleared if current thread is interrupted during shutdown
*/
public static void shutdownNow(ExecutorService service) {
service.shutdownNow();
awaitTermination(service);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy