mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-24 03:35:58 +00:00
Introduce thread priorities for threads and handlerthreads.
This commit is contained in:
@@ -2,6 +2,7 @@ package org.signal.core.util;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Process;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
@@ -18,6 +19,20 @@ import java.util.concurrent.ExecutorService;
|
||||
*/
|
||||
public final class ThreadUtil {
|
||||
|
||||
/**
|
||||
* Default background thread priority.
|
||||
*/
|
||||
public static final int PRIORITY_BACKGROUND_THREAD = Process.THREAD_PRIORITY_BACKGROUND;
|
||||
/**
|
||||
* Important background thread priority. This is slightly lower priority than the UI thread. Use for critical work that should run as fast as
|
||||
* possible, but shouldn't block the UI (e.g. message sends)
|
||||
*/
|
||||
public static final int PRIORITY_IMPORTANT_BACKGROUND_THREAD = Process.THREAD_PRIORITY_DEFAULT + Process.THREAD_PRIORITY_LESS_FAVORABLE;
|
||||
/**
|
||||
* As important as the UI thread. Use for absolutely critical UI blocking tasks/threads. For example fetching data for display in a recyclerview, or
|
||||
* anything that will block UI.
|
||||
*/
|
||||
public static final int PRIORITY_UI_BLOCKING_THREAD = Process.THREAD_PRIORITY_DEFAULT;
|
||||
private static volatile Handler handler;
|
||||
|
||||
@VisibleForTesting
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.signal.core.util.concurrent;
|
||||
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Process;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
@@ -17,15 +18,20 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public final class SignalExecutors {
|
||||
|
||||
public static final ExecutorService UNBOUNDED = ThreadUtil.trace(Executors.newCachedThreadPool(new NumberedThreadFactory("signal-unbounded")));
|
||||
public static final ExecutorService BOUNDED = ThreadUtil.trace(Executors.newFixedThreadPool(4, new NumberedThreadFactory("signal-bounded")));
|
||||
public static final ExecutorService SERIAL = ThreadUtil.trace(Executors.newSingleThreadExecutor(new NumberedThreadFactory("signal-serial")));
|
||||
public static final ExecutorService BOUNDED_IO = ThreadUtil.trace(newCachedBoundedExecutor("signal-io-bounded", 1, 32, 30));
|
||||
public static final ExecutorService UNBOUNDED = ThreadUtil.trace(Executors.newCachedThreadPool(new NumberedThreadFactory("signal-unbounded", ThreadUtil.PRIORITY_BACKGROUND_THREAD)));
|
||||
public static final ExecutorService BOUNDED = ThreadUtil.trace(Executors.newFixedThreadPool(4, new NumberedThreadFactory("signal-bounded", ThreadUtil.PRIORITY_BACKGROUND_THREAD)));
|
||||
public static final ExecutorService SERIAL = ThreadUtil.trace(Executors.newSingleThreadExecutor(new NumberedThreadFactory("signal-serial", ThreadUtil.PRIORITY_BACKGROUND_THREAD)));
|
||||
public static final ExecutorService BOUNDED_IO = ThreadUtil.trace(newCachedBoundedExecutor("signal-io-bounded", ThreadUtil.PRIORITY_IMPORTANT_BACKGROUND_THREAD, 1, 32, 30));
|
||||
|
||||
private SignalExecutors() {}
|
||||
|
||||
public static ExecutorService newCachedSingleThreadExecutor(final String name) {
|
||||
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 15, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), r -> new Thread(r, name));
|
||||
public static ExecutorService newCachedSingleThreadExecutor(final String name, int priority) {
|
||||
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 15, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), r -> new Thread(r, name) {
|
||||
@Override public void run() {
|
||||
Process.setThreadPriority(priority);
|
||||
super.run();
|
||||
}
|
||||
});
|
||||
executor.allowCoreThreadTimeOut(true);
|
||||
return executor;
|
||||
}
|
||||
@@ -41,7 +47,7 @@ public final class SignalExecutors {
|
||||
* So we make a queue that will always return false if it's non-empty to ensure new threads get
|
||||
* created. Then, if a task gets rejected, we simply add it to the queue.
|
||||
*/
|
||||
public static ExecutorService newCachedBoundedExecutor(final String name, int minThreads, int maxThreads, int timeoutSeconds) {
|
||||
public static ExecutorService newCachedBoundedExecutor(final String name, int priority, int minThreads, int maxThreads, int timeoutSeconds) {
|
||||
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(minThreads,
|
||||
maxThreads,
|
||||
timeoutSeconds,
|
||||
@@ -55,7 +61,7 @@ public final class SignalExecutors {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}, new NumberedThreadFactory(name));
|
||||
}, new NumberedThreadFactory(name, priority));
|
||||
|
||||
threadPool.setRejectedExecutionHandler((runnable, executor) -> {
|
||||
try {
|
||||
@@ -73,28 +79,36 @@ public final class SignalExecutors {
|
||||
* which processor work in FIFO order.
|
||||
*/
|
||||
public static ExecutorService newFixedLifoThreadExecutor(String name, int minThreads, int maxThreads) {
|
||||
return new ThreadPoolExecutor(minThreads, maxThreads, 0, TimeUnit.MILLISECONDS, new LinkedBlockingLifoQueue<>(), new NumberedThreadFactory(name));
|
||||
return new ThreadPoolExecutor(minThreads, maxThreads, 0, TimeUnit.MILLISECONDS, new LinkedBlockingLifoQueue<>(), new NumberedThreadFactory(name, ThreadUtil.PRIORITY_BACKGROUND_THREAD));
|
||||
}
|
||||
|
||||
public static HandlerThread getAndStartHandlerThread(@NonNull String name) {
|
||||
HandlerThread handlerThread = new HandlerThread(name);
|
||||
public static HandlerThread getAndStartHandlerThread(@NonNull String name, int priority) {
|
||||
HandlerThread handlerThread = new HandlerThread(name, priority);
|
||||
handlerThread.start();
|
||||
return handlerThread;
|
||||
}
|
||||
|
||||
private static class NumberedThreadFactory implements ThreadFactory {
|
||||
|
||||
private final int priority;
|
||||
private final String baseName;
|
||||
private final AtomicInteger counter;
|
||||
|
||||
NumberedThreadFactory(@NonNull String baseName) {
|
||||
NumberedThreadFactory(@NonNull String baseName, int priority) {
|
||||
this.priority = priority;
|
||||
this.baseName = baseName;
|
||||
this.counter = new AtomicInteger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(@NonNull Runnable r) {
|
||||
return new Thread(r, baseName + "-" + counter.getAndIncrement());
|
||||
return new Thread(r, baseName + "-" + counter.getAndIncrement()) {
|
||||
@Override
|
||||
public void run() {
|
||||
Process.setThreadPriority(priority);
|
||||
super.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user