Как реализовать очередь runnables

Я пытаюсь реализовать очередь runnables, которые будут выполняться один за другим (это означает, что следующий в очереди будет выполняться после завершения другого) во время асинхронной задачи. Я написал менеджер для управления этими исполняемыми и задачами, которые сами по себе являются исполняемыми. Затем я получаю первую задачу в асинхронной задаче и запускаю ее в надежде, что она пройдет через очередь, однако она просто дважды запускает первую исполняемую задачу. Может ли кто-нибудь помочь мне с кодом, с которым я работал, или указать мне пример, который может помочь?

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);
    }

person ninjasense    schedule 14.09.2011    source источник


Ответы (5)


как насчет использования Executors.newSingleThreadExecutor()? http://developer.android.com/reference/java/util/concurrent/Executors.html#newSingleThreadExecutor%28java.util.concurrent.ThreadFactory%29

В описании API поясняется, что этот исполнитель последовательно выполняет только одну задачу и имеет неограниченную очередь. Я думаю, что это может удовлетворить ваше требование.

person kingori    schedule 14.09.2011

Я делаю что-то очень похожее в одном из своих приложений, и то, что я делаю, чтобы сохранить его в чистоте, заключается в том, чтобы моя очередь содержала данные, а не потоки для выполнения. Я использую один AsyncTask для своего выполнения (который извлекается из пула потоков, который выделяет система... может упростить вам управление), и в его методе doInBackground я извлекаю данные из очереди, работаю с ними, и снова вызовите мой метод ввода в onPostExecute.

person Rich    schedule 14.09.2011

Нет необходимости создавать его самостоятельно, просто используйте ThreadPoolExecutor для сделать это для вас. создайте один с размером minPool 1 и максимальным размером пула 15, и все должно быть готово.

person superfell    schedule 14.09.2011
comment
Что произойдет, если количество запущенных объектов превысит миллиард? - person User3; 31.03.2017

Почему бы вам не использовать Queue вместо ArrayLists? Сюда бы лучше вписался.

person andreas    schedule 14.09.2011

ArrayList не является потокобезопасным, но вы используете его с потоками. Таким образом, у вас есть разные потоки, мешающие друг другу. Вот что, вероятно, происходит:

  • Вы вызываете push несколько раз с различными runnables. Метод add вызывается несколько одновременно для всех из них, но поскольку add не является потокобезопасным, первый не заканчивает добавление до того, как второй начнет добавлять, поэтому в вашей очереди останется только один runnable.

  • Затем StartNext вызывается несколько раз одновременно. Один из потоков выполняет «next = queue.Get()», однако другой поток также вызывает «next = queue.Get()» до того, как первый поток сможет удалить этот элемент из очереди, поэтому оба потока заканчивают обработку такой же работоспособный.

Вам нужно будет либо найти потокобезопасный объект для использования, либо добавить какой-либо тип мьютекса/механизма блокировки, чтобы гарантировать, что различные потоки не мешают друг другу.

person CodeThug    schedule 14.09.2011