diff --git a/java/src/com/android/inputmethod/latin/ContactsContentObserver.java b/java/src/com/android/inputmethod/latin/ContactsContentObserver.java
index 4a8d1133b2962b7872c6b242b58043aff36e71de..5eb9b16d1f77221d61bbaf1803042e78c21ddcfe 100644
--- a/java/src/com/android/inputmethod/latin/ContactsContentObserver.java
+++ b/java/src/com/android/inputmethod/latin/ContactsContentObserver.java
@@ -56,8 +56,8 @@ public class ContactsContentObserver implements Runnable {
         mContentObserver = new ContentObserver(null /* handler */) {
             @Override
             public void onChange(boolean self) {
-                // TODO(zivkovic): Schedule a separate task to reset the decoder.
-                ExecutorUtils.getBackgroundExecutor().execute(ContactsContentObserver.this);
+                ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD)
+                        .execute(ContactsContentObserver.this);
             }
         };
         final ContentResolver contentResolver = mContext.getContentResolver();
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
index 2f3c582516e0f49004814501aa84197f58c510c5..a59253aadcacb6624791c52e7617003e6e1a3566 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
@@ -338,7 +338,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
             final Locale locale, final DictionaryInitializationListener listener) {
         final CountDownLatch latchForWaitingLoadingMainDictionary = new CountDownLatch(1);
         mLatchForWaitingLoadingMainDictionaries = latchForWaitingLoadingMainDictionary;
-        ExecutorUtils.getBackgroundExecutor().execute(new Runnable() {
+        ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute(new Runnable() {
             @Override
             public void run() {
                 doReloadUninitializedMainDictionaries(
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 138a2ea5c29247a87b72d6794ef4eb1d6178ae6f..fa8fb20288cc49e5d6262fce9dc0a069c5b4aaae 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -168,7 +168,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
     }
 
     private static void asyncExecuteTaskWithLock(final Lock lock, final Runnable task) {
-        ExecutorUtils.getBackgroundExecutor().execute(new Runnable() {
+        ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute(new Runnable() {
             @Override
             public void run() {
                 lock.lock();
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/UserDictionaryLookup.java b/java/src/com/android/inputmethod/latin/spellcheck/UserDictionaryLookup.java
index 6ab741ca1ab06ee8fac7e333b19cab916688e352..f2491f4785f856d517c80672659bcd319a484313 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/UserDictionaryLookup.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/UserDictionaryLookup.java
@@ -143,8 +143,8 @@ public class UserDictionaryLookup implements Closeable {
             }
 
             // Schedule a new reload after RELOAD_DELAY_MS.
-            mReloadFuture = ExecutorUtils.getBackgroundExecutor().schedule(
-                    mLoader, RELOAD_DELAY_MS, TimeUnit.MILLISECONDS);
+            mReloadFuture = ExecutorUtils.getBackgroundExecutor(ExecutorUtils.SPELLING)
+                    .schedule(mLoader, RELOAD_DELAY_MS, TimeUnit.MILLISECONDS);
         }
     }
     private final ContentObserver mObserver = new UserDictionaryContentObserver();
@@ -186,7 +186,7 @@ public class UserDictionaryLookup implements Closeable {
         // Schedule the initial load to run immediately.  It's possible that the first call to
         // isValidWord occurs before the dictionary has actually loaded, so it should not
         // assume that the dictionary has been loaded.
-        ExecutorUtils.getBackgroundExecutor().execute(mLoader);
+        ExecutorUtils.getBackgroundExecutor(ExecutorUtils.SPELLING).execute(mLoader);
 
         // Register the observer to be notified on changes to the UserDictionary and all individual
         // items.
diff --git a/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java b/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java
index a78446103a9853998e23743a9686c1a68581b597..8ce6eff9296e99c06a33ec7f2d7229762a8eb50b 100644
--- a/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java
@@ -33,17 +33,30 @@ public class ExecutorUtils {
 
     private static final String TAG = "ExecutorUtils";
 
-    private static ScheduledExecutorService sExecutorService =
-            Executors.newSingleThreadScheduledExecutor(new ExecutorFactory());
+    public static final String KEYBOARD = "Keyboard";
+    public static final String SPELLING = "Spelling";
+
+    private static ScheduledExecutorService sKeyboardExecutorService = newExecutorService(KEYBOARD);
+    private static ScheduledExecutorService sSpellingExecutorService = newExecutorService(SPELLING);
+
+    private static ScheduledExecutorService newExecutorService(final String name) {
+        return Executors.newSingleThreadScheduledExecutor(new ExecutorFactory(name));
+    }
 
     private static class ExecutorFactory implements ThreadFactory {
+        private final String mName;
+
+        private ExecutorFactory(final String name) {
+            mName = name;
+        }
+
         @Override
         public Thread newThread(final Runnable runnable) {
             Thread thread = new Thread(runnable, TAG);
             thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
                 @Override
                 public void uncaughtException(Thread thread, Throwable ex) {
-                    Log.w(TAG + "-" + runnable.getClass().getSimpleName(), ex);
+                    Log.w(mName + "-" + runnable.getClass().getSimpleName(), ex);
                 }
             });
             return thread;
@@ -64,24 +77,44 @@ public class ExecutorUtils {
     //
 
     /**
+     * @param name Executor's name.
      * @return scheduled executor service used to run background tasks
      */
-    public static ScheduledExecutorService getBackgroundExecutor() {
+    public static ScheduledExecutorService getBackgroundExecutor(final String name) {
         if (sExecutorServiceForTests != null) {
             return sExecutorServiceForTests;
         }
-        return sExecutorService;
+        switch (name) {
+            case KEYBOARD:
+                return sKeyboardExecutorService;
+            case SPELLING:
+                return sSpellingExecutorService;
+            default:
+                throw new IllegalArgumentException("Invalid executor: " + name);
+        }
     }
 
-    public static void killTasks() {
-        getBackgroundExecutor().shutdownNow();
+    public static void killTasks(final String name) {
+        final ScheduledExecutorService executorService = getBackgroundExecutor(name);
+        executorService.shutdownNow();
         try {
-            getBackgroundExecutor().awaitTermination(5, TimeUnit.SECONDS);
+            executorService.awaitTermination(5, TimeUnit.SECONDS);
         } catch (InterruptedException e) {
-            Log.wtf(TAG, "Failed to shut down background task.");
-            throw new IllegalStateException("Failed to shut down background task.");
-        } finally {
-            sExecutorService = Executors.newSingleThreadScheduledExecutor(new ExecutorFactory());
+            Log.wtf(TAG, "Failed to shut down: " + name);
+        }
+        if (executorService == sExecutorServiceForTests) {
+            // Don't do anything to the test service.
+            return;
+        }
+        switch (name) {
+            case KEYBOARD:
+                sKeyboardExecutorService = newExecutorService(KEYBOARD);
+                break;
+            case SPELLING:
+                sSpellingExecutorService = newExecutorService(SPELLING);
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid executor: " + name);
         }
     }
 
diff --git a/tests/src/com/android/inputmethod/latin/utils/ExecutorUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/ExecutorUtilsTests.java
index d722151cf8ef298647a59a1a80cae4ce9fb56755..86923059b3aa4e1ef431b68d077a5b1f8902c279 100644
--- a/tests/src/com/android/inputmethod/latin/utils/ExecutorUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/ExecutorUtilsTests.java
@@ -35,7 +35,8 @@ public class ExecutorUtilsTests extends AndroidTestCase {
     private static final int DELAY_FOR_WAITING_TASKS_MILLISECONDS = 500;
 
     public void testExecute() {
-        final ExecutorService executor = ExecutorUtils.getBackgroundExecutor();
+        final ExecutorService executor =
+                ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD);
         final AtomicInteger v = new AtomicInteger(0);
         for (int i = 0; i < NUM_OF_TASKS; ++i) {
             executor.execute(new Runnable() {