【问题标题】:How to implement a queue of runnables如何实现可运行的队列
【发布时间】:2011-09-14 15:02:39
【问题描述】:

我正在尝试实现一个可运行队列,以便在异步任务期间一个接一个地执行(意味着队列中的下一个将在另一个完成后执行)。我写了一个管理器来管理这些可运行的和本身就是可运行的任务。然后我得到异步任务中的第一个任务并运行它,希望它能够通过队列运行,但是它最终只运行了第一个可运行对象两次。任何人都可以帮助我处理我一直在使用的代码,或者指出一个可能有帮助的例子吗?

public class ConnectionManager {

    public static final int MAX_CONNECTIONS = 15;

    private ArrayList<Runnable> active = new ArrayList<Runnable>();
    private ArrayList<Runnable> queue = new ArrayList<Runnable>();

    private static ConnectionManager instance;

    public static ConnectionManager getInstance() {
        if (instance == null)
            instance = new ConnectionManager();
        return instance;
    }

    public void push(Runnable runnable) {
        queue.add(runnable);
        if (active.size() < MAX_CONNECTIONS)
            startNext();
    }

    private void startNext() {
        if (!queue.isEmpty()) {
            Runnable next = queue.get(0);
            queue.remove(0);
            active.add(next);

            Thread thread = new Thread(next);
            thread.start();
        }
    }

    public void didComplete(Runnable runnable) {
        active.remove(runnable);
        startNext();
    }
}

public class Task implements Runnable {
    Context con;
    String xmlFile;
    File taskFile;
    String Id;

    public void create(Context context, String xml, File task, String id) {
        this.con = context;
        this.xmlFile = xml;
        this.taskFile = task;
        this.Id = id;
        ConnectionManager.getInstance().push(this);
    }

    @Override
    public void run() {
        User.SendTask(con, xmlFile, taskFile, Id);

        ConnectionManager.getInstance().didComplete(this);
    }

【问题讨论】:

    标签: java android queue runnable


    【解决方案1】:

    使用 Executors.newSingleThreadExecutor() 怎么样? http://developer.android.com/reference/java/util/concurrent/Executors.html#newSingleThreadExecutor%28java.util.concurrent.ThreadFactory%29

    API 描述说明此执行器仅顺序执行一个任务,并且具有无限队列。我觉得这个可以满足你的要求。

    【讨论】:

      【解决方案2】:

      我正在我的一个应用程序中做一些非常相似的事情,我要保持它干净的是让我的队列包含数据而不是要执行的线程。我使用单个 AsyncTask 执行我的执行(它从系统分配的线程池中提取......可能会让你更容易管理 mgmt),并且在它的 doInBackground 方法中,我将数据拉出队列,对其进行操作,并在 onPostExecute 中再次调用我的入口方法。

      【讨论】:

        【解决方案3】:

        无需自己构建,只需使用ThreadPoolExecutor 为您完成即可。构建一个 minPool 大小为 1,最大池大小为 15 的一个,你应该已经准备好了。

        【讨论】:

        • 如果可运行对象堆积超过十亿会怎样?
        【解决方案4】:

        为什么不使用Queue 而不是 ArrayLists?它更适合这里。

        【讨论】:

          【解决方案5】:

          ArrayList 不是线程安全的,但您将它与线程一起使用。因此,您有不同的线程相互干扰。以下是可能发生的情况:

          • 您多次调用 push 和各种 runnables。对于所有这些,add 方法在某种程度上同时被调用,但是因为 add 不是线程安全的,所以第一个在第二个开始添加之前没有完成添加,所以你最终只能在队列中运行一个。

          • 然后 StartNext 被同时调用了很多次。其中一个线程运行“next = queue.Get()”,但是,另一个线程在第一个线程有机会从队列中删除该项目之前也调用“next = queue.Get()”,因此两个线程最终都会处理相同的可运行文件。

          您需要找到要使用的线程安全对象,或者添加某种类型的互斥/锁定机制,以确保各个线程不会相互干扰。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-09-03
            • 2016-01-02
            相关资源
            最近更新 更多