aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java
diff options
context:
space:
mode:
authorDan Zivkovic <zivkovic@google.com>2015-02-17 15:12:05 -0800
committerDan Zivkovic <zivkovic@google.com>2015-02-19 11:40:57 -0800
commit0b03f13cabec84d2d841fde47ce9fec0d531b6a1 (patch)
tree5cc14dea6693025f25d279dd59140c04d0d7495f /java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java
parent95711bfcee07d848883316cf07439408f5b332a1 (diff)
downloadlatinime-0b03f13cabec84d2d841fde47ce9fec0d531b6a1.tar.gz
latinime-0b03f13cabec84d2d841fde47ce9fec0d531b6a1.tar.xz
latinime-0b03f13cabec84d2d841fde47ce9fec0d531b6a1.zip
Sanitize the usage of executors.
There should be 1 executor each for static and dynamic language models. This prevents too many dynamic LM updates from running in parallel, competing for resources. Change-Id: I8ec439e0ea2d92fba275bc20a0b8c9193346a0c1
Diffstat (limited to 'java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java')
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java88
1 files changed, 67 insertions, 21 deletions
diff --git a/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java b/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java
index 50be16072..c533a6273 100644
--- a/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java
@@ -16,10 +16,12 @@
package com.android.inputmethod.latin.utils;
+import android.util.Log;
+
import com.android.inputmethod.annotations.UsedForTesting;
+import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
@@ -28,33 +30,49 @@ import java.util.concurrent.ThreadFactory;
* Utilities to manage executors.
*/
public class ExecutorUtils {
- static final ConcurrentHashMap<String, ScheduledExecutorService> sExecutorMap =
+
+ private static final String STATIC_LANGUAGE_MODEL_UPDATE = "StaticLanguageModelUpdate";
+ private static final String DYNAMIC_LANGUAGE_MODEL_UPDATE = "DynamicLanguageModelUpdate";
+
+ private static final ConcurrentHashMap<String, ScheduledExecutorService> sExecutorMap =
new ConcurrentHashMap<>();
- private static class ThreadFactoryWithId implements ThreadFactory {
- private final String mId;
+ @UsedForTesting
+ private static ScheduledExecutorService sExecutorServiceForTests;
- public ThreadFactoryWithId(final String id) {
- mId = id;
- }
+ @UsedForTesting
+ public static void setExecutorServiceForTests(
+ final ScheduledExecutorService executorServiceForTests) {
+ sExecutorServiceForTests = executorServiceForTests;
+ }
- @Override
- public Thread newThread(final Runnable r) {
- return new Thread(r, "Executor - " + mId);
- }
+ /**
+ * @return scheduled executor service used to update static language models
+ */
+ public static ScheduledExecutorService getExecutorForStaticLanguageModelUpdate() {
+ return getExecutor(STATIC_LANGUAGE_MODEL_UPDATE);
+ }
+
+ /**
+ * @return scheduled executor service used to update dynamic language models
+ */
+ public static ScheduledExecutorService getExecutorForDynamicLanguageModelUpdate() {
+ return getExecutor(DYNAMIC_LANGUAGE_MODEL_UPDATE);
}
/**
* Gets the executor for the given id.
*/
- public static ScheduledExecutorService getExecutor(final String id) {
+ private static ScheduledExecutorService getExecutor(final String id) {
+ if (sExecutorServiceForTests != null) {
+ return sExecutorServiceForTests;
+ }
ScheduledExecutorService executor = sExecutorMap.get(id);
if (executor == null) {
synchronized (sExecutorMap) {
executor = sExecutorMap.get(id);
if (executor == null) {
- executor = Executors.newSingleThreadScheduledExecutor(
- new ThreadFactoryWithId(id));
+ executor = Executors.newSingleThreadScheduledExecutor(new ExecutorFactory(id));
sExecutorMap.put(id, executor);
}
}
@@ -69,14 +87,42 @@ public class ExecutorUtils {
public static void shutdownAllExecutors() {
synchronized (sExecutorMap) {
for (final ScheduledExecutorService executor : sExecutorMap.values()) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- executor.shutdown();
- sExecutorMap.remove(executor);
- }
- });
+ executor.execute(new ExecutorShutdown(executor));
}
+ sExecutorMap.clear();
+ }
+ }
+
+ private static class ExecutorFactory implements ThreadFactory {
+ private final String mThreadName;
+
+ public ExecutorFactory(final String threadName) {
+ mThreadName = threadName;
+ }
+
+ @Override
+ public Thread newThread(final Runnable runnable) {
+ Thread thread = new Thread(runnable, mThreadName);
+ thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
+ @Override
+ public void uncaughtException(Thread thread, Throwable ex) {
+ Log.w(mThreadName + "-" + runnable.getClass().getSimpleName(), ex);
+ }
+ });
+ return thread;
+ }
+ }
+
+ private static class ExecutorShutdown implements Runnable {
+ private final ScheduledExecutorService mExecutor;
+
+ public ExecutorShutdown(final ScheduledExecutorService executor) {
+ mExecutor = executor;
+ }
+
+ @Override
+ public void run() {
+ mExecutor.shutdown();
}
}
}