Как реализовать очередь из runnables - PullRequest
5 голосов
/ 14 сентября 2011

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

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 ]

13 голосов
/ 14 сентября 2011

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

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

2 голосов
/ 14 сентября 2011

Почему бы вам не использовать Очередь вместо ArrayLists? Это было бы лучше здесь.

2 голосов
/ 14 сентября 2011

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

2 голосов
/ 14 сентября 2011

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

1 голос
/ 14 сентября 2011

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

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

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

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

...