Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.inputmethod.latin.utils;
     18 
     19 import java.util.Queue;
     20 import java.util.concurrent.ArrayBlockingQueue;
     21 import java.util.concurrent.ConcurrentLinkedQueue;
     22 import java.util.concurrent.ThreadPoolExecutor;
     23 import java.util.concurrent.TimeUnit;
     24 
     25 /**
     26  * An object that executes submitted tasks using a thread.
     27  */
     28 public class PrioritizedSerialExecutor {
     29     public static final String TAG = PrioritizedSerialExecutor.class.getSimpleName();
     30 
     31     private final Object mLock = new Object();
     32 
     33     private final Queue<Runnable> mTasks;
     34     private final Queue<Runnable> mPrioritizedTasks;
     35     private boolean mIsShutdown;
     36     private final ThreadPoolExecutor mThreadPoolExecutor;
     37 
     38     // The task which is running now.
     39     private Runnable mActive;
     40 
     41     public PrioritizedSerialExecutor() {
     42         mTasks = new ConcurrentLinkedQueue<Runnable>();
     43         mPrioritizedTasks = new ConcurrentLinkedQueue<Runnable>();
     44         mIsShutdown = false;
     45         mThreadPoolExecutor = new ThreadPoolExecutor(1 /* corePoolSize */, 1 /* maximumPoolSize */,
     46                 0 /* keepAliveTime */, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1));
     47     }
     48 
     49     /**
     50      * Clears all queued tasks.
     51      */
     52     public void clearAllTasks() {
     53         synchronized(mLock) {
     54             mTasks.clear();
     55             mPrioritizedTasks.clear();
     56         }
     57     }
     58 
     59     /**
     60      * Enqueues the given task into the task queue.
     61      * @param r the enqueued task
     62      */
     63     public void execute(final Runnable r) {
     64         synchronized(mLock) {
     65             if (!mIsShutdown) {
     66                 mTasks.offer(new Runnable() {
     67                     @Override
     68                     public void run() {
     69                         try {
     70                             r.run();
     71                         } finally {
     72                             scheduleNext();
     73                         }
     74                     }
     75                 });
     76                 if (mActive == null) {
     77                     scheduleNext();
     78                 }
     79             }
     80         }
     81     }
     82 
     83     /**
     84      * Enqueues the given task into the prioritized task queue.
     85      * @param r the enqueued task
     86      */
     87     public void executePrioritized(final Runnable r) {
     88         synchronized(mLock) {
     89             if (!mIsShutdown) {
     90                 mPrioritizedTasks.offer(new Runnable() {
     91                     @Override
     92                     public void run() {
     93                         try {
     94                             r.run();
     95                         } finally {
     96                             scheduleNext();
     97                         }
     98                     }
     99                 });
    100                 if (mActive == null) {
    101                     scheduleNext();
    102                 }
    103             }
    104         }
    105     }
    106 
    107     private boolean fetchNextTasksLocked() {
    108         mActive = mPrioritizedTasks.poll();
    109         if (mActive == null) {
    110             mActive = mTasks.poll();
    111         }
    112         return mActive != null;
    113     }
    114 
    115     private void scheduleNext() {
    116         synchronized(mLock) {
    117             if (fetchNextTasksLocked()) {
    118                 mThreadPoolExecutor.execute(mActive);
    119             }
    120         }
    121     }
    122 
    123     public void remove(final Runnable r) {
    124         synchronized(mLock) {
    125             mTasks.remove(r);
    126             mPrioritizedTasks.remove(r);
    127         }
    128     }
    129 
    130     public void replaceAndExecute(final Runnable oldTask, final Runnable newTask) {
    131         synchronized(mLock) {
    132             if (oldTask != null) remove(oldTask);
    133             execute(newTask);
    134         }
    135     }
    136 
    137     public void shutdown() {
    138         synchronized(mLock) {
    139             mIsShutdown = true;
    140         }
    141     }
    142 
    143     public boolean isTerminated() {
    144         synchronized(mLock) {
    145             if (!mIsShutdown) {
    146                 return false;
    147             }
    148             return mPrioritizedTasks.isEmpty() && mTasks.isEmpty() && mActive == null;
    149         }
    150     }
    151 }
    152