我正在尝试在异步任务期间实现一个接一个地执行的runnables队列(意味着队列中的下一个将在另一个完成后执行)。我写了一个管理器来管理这些可运行的任务和任务。然后我在异步任务中获得第一个任务并运行它,希望它将通过队列运行,但是它最终会运行第一个runnable两次。任何人都可以帮助我使用我一直在使用的代码或指向一个可能有所帮助的示例吗?
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);
}
答案 0 :(得分:13)
如何使用Executors.newSingleThreadExecutor()? http://developer.android.com/reference/java/util/concurrent/Executors.html#newSingleThreadExecutor%28java.util.concurrent.ThreadFactory%29
API描述说明此执行程序只按顺序执行一个任务并具有无限制的队列。我认为这个可以满足你的要求。
答案 1 :(得分:2)
我在我的一个应用程序中做了非常相似的事情,而我要保持清洁的是让我的队列包含数据而不是要执行的线程。我使用单个AsyncTask执行(从系统分配的线程池中提取...可能会使mgmt更容易),并且在doInBackground方法中,我将数据拉出队列,对其进行操作,并在onPostExecute中再次调用我的入口方法。
答案 2 :(得分:2)
没有必要自己构建,只需使用ThreadPoolExecutor为您完成。构造一个minPool大小为1,最大池大小为15,你应该全部设置。
答案 3 :(得分:2)
为什么不使用Queue而不是ArrayLists?它会更适合这里。
答案 4 :(得分:1)
ArrayList不是线程安全的,但是你将它与线程一起使用。因此,您有不同的线程以彼此的方式进入。这是可能发生的事情:
您使用各种runnables多次调用push。对于所有这些,add方法会稍微同时调用,但因为add不是线程安全的,所以第一个方法在第二个开始添加之前没有完成添加,所以你最终只能在队列中运行一个runnable。
然后同时调用StartNext一堆。其中一个线程运行“next = queue.Get(),但是,在第一个线程有机会从队列中删除该项目之前,另一个线程也调用”next = queue.Get()“,因此两个线程最终都会处理同样的可运行。
您需要找到要使用的线程安全对象,或添加某种类型的互斥锁/锁定机制,以确保各个线程不会互相攻击。