如何实现一个可运行队列

5
我正在尝试实现一个可执行的 Runnable 队列,以便在异步任务期间按顺序执行(即下一个在队列中的 Runnable 将在前一个完成后执行)。我编写了一个 Manager 来管理这些可运行任务和任务本身是一个可运行的。然后我获取异步任务中的第一个任务并运行它,希望它会通过队列运行,但它最终只会运行第一个可运行任务两次。有人能够帮助我审查一下我已经编写的代码或者指导一下我类似问题的示例吗?
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);
    }
5个回答

15

2

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


2

无需自己构建,只需使用ThreadPoolExecutor即可。将其构造为最小池大小为1,最大池大小为15,就可以了。


如果可运行对象堆积超过十亿会发生什么? - User3

2
为什么不使用 队列 而是使用 ArrayLists 呢?它更适合这里。

1
ArrayList不是线程安全的,但你在使用它时涉及了多线程。因此,不同的线程会互相影响。以下可能是发生的情况:
- 你多次调用push方法,传递了不同的runnable。这些调用中的add方法几乎同时被调用,但由于add方法不是线程安全的,第一个调用在第二个调用开始之前还没有完成添加,因此最终只有一个runnable被添加到队列中。
- 然后,StartNext方法被同时调用多次。其中一个线程执行"next = queue.Get()",然而另一个线程在第一个线程有机会从队列中移除该项之前也调用了"next = queue.Get()",所以两个线程最终都会处理相同的runnable。
为了解决这个问题,你可以选择使用线程安全的对象,或者添加一些互斥锁/同步机制,确保各个线程不会相互干扰。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接