AsyncTask on Executor and PriorityBlockingQueue implementation issue

偶尔善良 提交于 2019-12-02 08:35:58

As you may have noticed while looking through the AsyncTask implementation, it internally uses a FutureTask to handle the background task, and that is what gets handed on to the Executor and potentially queued on it's work queue. Since you are already deriving your own implementation, you could replace the FutureTask with a custom derivative that holds a reference to the AsyncTask, to be accessed from your Comparator implementation.

Also, instead of replacing the default static Executor of your custom AsyncTask derivative, you should instead use the executeOnExecutor() method in your subclasses so that it can be used in a generic manner.

CustomAsyncTask, like AsyncTask, uses a static queue. Everything that goes on that queue, at present, will run through your DownloadTasksComparator. However, DownloadTasksComparator only works with DownloadTask. So long as you only use DownloadTask, and not other subclasses of CustomAsyncTask, you will be fine. However, apparently you have some other anonymous inner class extending CustomAsyncTask, and that's not a DownloadTask.

Make CustomAsyncTask be abstract, with a getPriority() method as an abstract method. Rename DownloadTasksComparator to CustomAsyncTaskComparator and have it compare CustomAsyncTask instances. Then, your other subclasses of CustomAsyncTask would need to implement their own getPriority() methods, to enable them to be sorted along with the DownloadTask instances in your work queue.

The problem is the PriorityBlockingQueue<CustomAsyncTask> you use to construct the ThreadPoolExecutor. ThreadPoolExecutor should accept BlockingQueue<Runnable>. ThreadPoolExecutor uses this queue to queue the runnables (runnables are submitted by calling execute(Runnable r)).

In AsyncTask's case, it calls Executor.execute(Runnable r) with a FutureTask object, so it's this FutureTask object being queued by the executor, not AsyncTask itself. So when the comparator tries to cast runnable to DownloadTask, the exception is thrown. I guess my.pkg.name.CustomAsyncTask$3 may be an inner runnable class.

Here is part of the source code of AsyncTask:

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
        Params... params) {
    if (mStatus != Status.PENDING) {
        switch (mStatus) {
            case RUNNING:
                throw new IllegalStateException("Cannot execute task:"
                        + " the task is already running.");
            case FINISHED:
                throw new IllegalStateException("Cannot execute task:"
                        + " the task has already been executed "
                        + "(a task can be executed only once)");
        }
    }

    mStatus = Status.RUNNING;

    onPreExecute();

    mWorker.mParams = params;
    exec.execute(mFuture);

    return this;
}

If you're trying to run AsyncTask with priority using this PriorityBlockingQueue approach, you should subclass the runnable object passed to the execute method, making it with a priority. You are using a custom asynctask, so you have full control of the variables.

To those trying to run the original AsyncTask with priority, i don't think there are much can be done. AsyncTask "execute" a private member variable mFuture, your hands are tied.

I am currently working on a similar problem, but in my case the "priority" is the timestamp, and i can set it in the runnable implementation, so it's kind of unrestricted by AsyncTask.

This is my code, just in case it might help someone. Sorry for my poor English!

/* Executor used by AsyncTask. Use it with executeOnExecutor()*/
class PriorityExecutor extends ThreadPoolExecutor{

    //workQueue is a instance of PriorityBlockingQueue<Runnable>
    public PriorityExecutor(int corePoolSize, int maximumPoolSize,
            long keepAliveTime, TimeUnit unit,
            BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,threadFactory);

    }

    //wrap the runnable passed in.
    @Override
    public void execute(Runnable command) {
        super.execute(new PriorityRunnableWrapper(command));
    }
}

//a wrapper class
class PriorityRunnableWrapper implements Runnable ,Comparable<PriorityRunnableWrapper>{

    long addedTime;//the "priority"
    Runnable r;

    public PriorityRunnableWrapper(Runnable r){
        this.r = r;
        addedTime = System.nanoTime();//in my case the timestamp is the priority
    }

    @Override
    public void run() {
        r.run();
    }

    @Override
    public int compareTo(PriorityRunnableWrapper another) {
        if(addedTime == another.addedTime)return 0;
        return addedTime - another.addedTime > 0 ? -1 : 1;
    }

}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!