mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
Migrated concurrency module from Java to Kotiln (#6110)
* Rename .java to .kt * Migrated concurrency module to Kotlin
This commit is contained in:
parent
fdbe504ca9
commit
87a453cb72
8 changed files with 190 additions and 193 deletions
|
|
@ -1,23 +0,0 @@
|
||||||
package fr.free.nrw.commons.concurrency;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.BuildConfig;
|
|
||||||
|
|
||||||
public class BackgroundPoolExceptionHandler implements ExceptionHandler {
|
|
||||||
/**
|
|
||||||
* If an exception occurs on a background thread, this handler will crash for debug builds
|
|
||||||
* but fail silently for release builds.
|
|
||||||
* @param t
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onException(@NonNull final Throwable t) {
|
|
||||||
//Crash for debug build
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
Thread thread = new Thread(() -> {
|
|
||||||
throw new RuntimeException(t);
|
|
||||||
});
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package fr.free.nrw.commons.concurrency
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.BuildConfig
|
||||||
|
|
||||||
|
|
||||||
|
class BackgroundPoolExceptionHandler : ExceptionHandler {
|
||||||
|
/**
|
||||||
|
* If an exception occurs on a background thread, this handler will crash for debug builds
|
||||||
|
* but fail silently for release builds.
|
||||||
|
* @param t
|
||||||
|
*/
|
||||||
|
override fun onException(t: Throwable) {
|
||||||
|
// Crash for debug build
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
val thread = Thread {
|
||||||
|
throw RuntimeException(t)
|
||||||
|
}
|
||||||
|
thread.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
package fr.free.nrw.commons.concurrency;
|
|
||||||
|
|
||||||
import java.util.concurrent.CancellationException;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.ThreadFactory;
|
|
||||||
|
|
||||||
class ExceptionAwareThreadPoolExecutor extends ScheduledThreadPoolExecutor {
|
|
||||||
|
|
||||||
private final ExceptionHandler exceptionHandler;
|
|
||||||
|
|
||||||
public ExceptionAwareThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory,
|
|
||||||
ExceptionHandler exceptionHandler) {
|
|
||||||
super(corePoolSize, threadFactory);
|
|
||||||
this.exceptionHandler = exceptionHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void afterExecute(Runnable r, Throwable t) {
|
|
||||||
super.afterExecute(r, t);
|
|
||||||
if (t == null && r instanceof Future<?>) {
|
|
||||||
try {
|
|
||||||
Future<?> future = (Future<?>) r;
|
|
||||||
if (future.isDone()) future.get();
|
|
||||||
} catch (CancellationException | InterruptedException e) {
|
|
||||||
//ignore
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
t = e.getCause() != null ? e.getCause() : e;
|
|
||||||
} catch (Exception e) {
|
|
||||||
t = e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t != null) {
|
|
||||||
exceptionHandler.onException(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
package fr.free.nrw.commons.concurrency
|
||||||
|
|
||||||
|
import java.util.concurrent.CancellationException
|
||||||
|
import java.util.concurrent.ExecutionException
|
||||||
|
import java.util.concurrent.Future
|
||||||
|
import java.util.concurrent.ScheduledThreadPoolExecutor
|
||||||
|
import java.util.concurrent.ThreadFactory
|
||||||
|
|
||||||
|
|
||||||
|
class ExceptionAwareThreadPoolExecutor(
|
||||||
|
corePoolSize: Int,
|
||||||
|
threadFactory: ThreadFactory,
|
||||||
|
private val exceptionHandler: ExceptionHandler?
|
||||||
|
) : ScheduledThreadPoolExecutor(corePoolSize, threadFactory) {
|
||||||
|
|
||||||
|
override fun afterExecute(r: Runnable, t: Throwable?) {
|
||||||
|
super.afterExecute(r, t)
|
||||||
|
var throwable = t
|
||||||
|
|
||||||
|
if (throwable == null && r is Future<*>) {
|
||||||
|
try {
|
||||||
|
if (r.isDone) {
|
||||||
|
r.get()
|
||||||
|
}
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
// ignore
|
||||||
|
} catch (e: InterruptedException) {
|
||||||
|
// ignore
|
||||||
|
} catch (e: ExecutionException) {
|
||||||
|
throwable = e.cause ?: e
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throwable = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throwable?.let {
|
||||||
|
exceptionHandler?.onException(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package fr.free.nrw.commons.concurrency;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
public interface ExceptionHandler {
|
|
||||||
void onException(@NonNull Throwable t);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package fr.free.nrw.commons.concurrency
|
||||||
|
|
||||||
|
interface ExceptionHandler {
|
||||||
|
|
||||||
|
fun onException(t: Throwable)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,124 +0,0 @@
|
||||||
package fr.free.nrw.commons.concurrency;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.ScheduledFuture;
|
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.ThreadFactory;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is a thread pool which provides some additional features:
|
|
||||||
* - it sets the thread priority to a value lower than foreground priority by default, or you can
|
|
||||||
* supply your own priority
|
|
||||||
* - it gives you a way to handle exceptions thrown in the thread pool
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class ThreadPoolService implements Executor {
|
|
||||||
private final ScheduledThreadPoolExecutor backgroundPool;
|
|
||||||
|
|
||||||
private ThreadPoolService(final Builder b) {
|
|
||||||
backgroundPool = new ExceptionAwareThreadPoolExecutor(b.poolSize,
|
|
||||||
new ThreadFactory() {
|
|
||||||
int count = 0;
|
|
||||||
@Override
|
|
||||||
public Thread newThread(@NonNull Runnable r) {
|
|
||||||
count++;
|
|
||||||
Thread t = new Thread(r, String.format("%s-%s", b.name, count));
|
|
||||||
//If the priority is specified out of range, we set the thread priority to Thread.MIN_PRIORITY
|
|
||||||
//It's done prevent IllegalArgumentException and to prevent setting of improper high priority for a less priority task
|
|
||||||
t.setPriority(b.priority > Thread.MAX_PRIORITY || b.priority < Thread.MIN_PRIORITY ?
|
|
||||||
Thread.MIN_PRIORITY : b.priority);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
}, b.exceptionHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long time, TimeUnit timeUnit) {
|
|
||||||
return backgroundPool.schedule(callable, time, timeUnit);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScheduledFuture<?> schedule(Runnable runnable) {
|
|
||||||
return schedule(runnable, 0, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScheduledFuture<?> schedule(Runnable runnable, long time, TimeUnit timeUnit) {
|
|
||||||
return backgroundPool.schedule(runnable, time, timeUnit);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScheduledFuture<?> scheduleAtFixedRate(final Runnable task, long initialDelay,
|
|
||||||
long period, final TimeUnit timeUnit) {
|
|
||||||
return backgroundPool.scheduleAtFixedRate(task, initialDelay, period, timeUnit);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScheduledThreadPoolExecutor executor() {
|
|
||||||
return backgroundPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shutdown(){
|
|
||||||
backgroundPool.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(Runnable command) {
|
|
||||||
backgroundPool.execute(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builder class for {@link ThreadPoolService}
|
|
||||||
*/
|
|
||||||
public static class Builder {
|
|
||||||
//Required
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
//Optional
|
|
||||||
private int poolSize = 1;
|
|
||||||
private int priority = Thread.MIN_PRIORITY;
|
|
||||||
private ExceptionHandler exceptionHandler = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param name the name of the threads in the service. if there are N threads,
|
|
||||||
* the thread names will be like name-1, name-2, name-3,...,name-N
|
|
||||||
*/
|
|
||||||
public Builder(@NonNull String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param poolSize the number of threads to keep in the pool
|
|
||||||
* @throws IllegalArgumentException if size of pool <=0
|
|
||||||
*/
|
|
||||||
public Builder setPoolSize(int poolSize) throws IllegalArgumentException {
|
|
||||||
if (poolSize <= 0) {
|
|
||||||
throw new IllegalArgumentException("Pool size must be grater than 0");
|
|
||||||
}
|
|
||||||
this.poolSize = poolSize;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param priority Priority of the threads in the service. You can supply a constant from
|
|
||||||
* {@link java.lang.Thread} or
|
|
||||||
* specify your own priority in the range 1(MIN_PRIORITY) to 10(MAX_PRIORITY)
|
|
||||||
* By default, the priority is set to {@link java.lang.Thread#MIN_PRIORITY}
|
|
||||||
*/
|
|
||||||
public Builder setPriority(int priority) {
|
|
||||||
this.priority = priority;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param handler The handler to use to handle exceptions in the service
|
|
||||||
*/
|
|
||||||
public Builder setExceptionHandler(ExceptionHandler handler) {
|
|
||||||
this.exceptionHandler = handler;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ThreadPoolService build() {
|
|
||||||
return new ThreadPoolService(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
package fr.free.nrw.commons.concurrency
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable
|
||||||
|
import java.util.concurrent.Executor
|
||||||
|
import java.util.concurrent.ScheduledFuture
|
||||||
|
import java.util.concurrent.ScheduledThreadPoolExecutor
|
||||||
|
import java.util.concurrent.ThreadFactory
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is a thread pool which provides some additional features:
|
||||||
|
* - it sets the thread priority to a value lower than foreground priority by default, or you can
|
||||||
|
* supply your own priority
|
||||||
|
* - it gives you a way to handle exceptions thrown in the thread pool
|
||||||
|
*/
|
||||||
|
class ThreadPoolService private constructor(builder: Builder) : Executor {
|
||||||
|
private val backgroundPool: ScheduledThreadPoolExecutor = ExceptionAwareThreadPoolExecutor(
|
||||||
|
builder.poolSize,
|
||||||
|
object : ThreadFactory {
|
||||||
|
private var count = 0
|
||||||
|
override fun newThread(r: Runnable): Thread {
|
||||||
|
count++
|
||||||
|
val t = Thread(r, "${builder.name}-$count")
|
||||||
|
// If the priority is specified out of range, we set the thread priority to
|
||||||
|
// Thread.MIN_PRIORITY
|
||||||
|
// It's done to prevent IllegalArgumentException and to prevent setting of
|
||||||
|
// improper high priority for a less priority task
|
||||||
|
t.priority =
|
||||||
|
if (
|
||||||
|
builder.priority > Thread.MAX_PRIORITY
|
||||||
|
||
|
||||||
|
builder.priority < Thread.MIN_PRIORITY
|
||||||
|
) {
|
||||||
|
Thread.MIN_PRIORITY
|
||||||
|
} else {
|
||||||
|
builder.priority
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
},
|
||||||
|
builder.exceptionHandler
|
||||||
|
)
|
||||||
|
|
||||||
|
fun <V> schedule(callable: Callable<V>, time: Long, timeUnit: TimeUnit): ScheduledFuture<V> {
|
||||||
|
return backgroundPool.schedule(callable, time, timeUnit)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun schedule(runnable: Runnable): ScheduledFuture<*> {
|
||||||
|
return schedule(runnable, 0, TimeUnit.SECONDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun schedule(runnable: Runnable, time: Long, timeUnit: TimeUnit): ScheduledFuture<*> {
|
||||||
|
return backgroundPool.schedule(runnable, time, timeUnit)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun scheduleAtFixedRate(
|
||||||
|
task: Runnable,
|
||||||
|
initialDelay: Long,
|
||||||
|
period: Long,
|
||||||
|
timeUnit: TimeUnit
|
||||||
|
): ScheduledFuture<*> {
|
||||||
|
return backgroundPool.scheduleWithFixedDelay(task, initialDelay, period, timeUnit)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun executor(): ScheduledThreadPoolExecutor {
|
||||||
|
return backgroundPool
|
||||||
|
}
|
||||||
|
|
||||||
|
fun shutdown() {
|
||||||
|
backgroundPool.shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun execute(command: Runnable) {
|
||||||
|
backgroundPool.execute(command)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder class for [ThreadPoolService]
|
||||||
|
*/
|
||||||
|
class Builder(val name: String) {
|
||||||
|
var poolSize: Int = 1
|
||||||
|
var priority: Int = Thread.MIN_PRIORITY
|
||||||
|
var exceptionHandler: ExceptionHandler? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param poolSize the number of threads to keep in the pool
|
||||||
|
* @throws IllegalArgumentException if size of pool <= 0
|
||||||
|
*/
|
||||||
|
fun setPoolSize(poolSize: Int): Builder {
|
||||||
|
if (poolSize <= 0) {
|
||||||
|
throw IllegalArgumentException("Pool size must be greater than 0")
|
||||||
|
}
|
||||||
|
this.poolSize = poolSize
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param priority Priority of the threads in the service. You can supply a constant from
|
||||||
|
* [java.lang.Thread] or
|
||||||
|
* specify your own priority in the range 1(MIN_PRIORITY)
|
||||||
|
* to 10(MAX_PRIORITY)
|
||||||
|
* By default, the priority is set to [java.lang.Thread.MIN_PRIORITY]
|
||||||
|
*/
|
||||||
|
fun setPriority(priority: Int): Builder {
|
||||||
|
this.priority = priority
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param handler The handler to use to handle exceptions in the service
|
||||||
|
*/
|
||||||
|
fun setExceptionHandler(handler: ExceptionHandler): Builder {
|
||||||
|
exceptionHandler = handler
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun build(): ThreadPoolService {
|
||||||
|
return ThreadPoolService(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue