如何实现可运行队列
我正在尝试实现一个可运行队列,在异步任务期间依次执行(意味着队列中的下一个将在另一个完成后执行)。我编写了一个管理器来管理这些可运行对象和本身就是可运行对象的任务。然后,我获取异步任务中的第一个任务并运行它,希望它能够在队列中运行,但是它最终只是运行第一个可运行对象两次。任何人都可以帮助我处理我一直在使用的代码,或者向我指出一个可能有帮助的示例吗?
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);
}
I am trying to implement a queue of runnables to be executed one after another(meaning the next in the queue will execute after the other has completed) during an asynchronous task. I wrote a Manager to manage these runnables and task that is a runnable itself. I then get the first task in the Asynchronous task and run it in hopes that it will run through the queue, however It just ends up running the first runnable twice. Can anyone help me with the code I have been working with or point me to an example that may be of some help?
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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
使用 Executors.newSingleThreadExecutor() 怎么样?
http://developer.android.com/reference/java/util/concurrent/Executors.html#newSingleThreadExecutor%28java.util.concurrent.ThreadFactory%29
API描述解释了这个执行器执行只有一个任务按顺序执行并且具有无限的队列。我想这个可以满足你的要求。
how about using Executors.newSingleThreadExecutor()?
http://developer.android.com/reference/java/util/concurrent/Executors.html#newSingleThreadExecutor%28java.util.concurrent.ThreadFactory%29
API description explains that this executor execute only one task sequentially and has unlimited queue. I think this one can satisfies your requirement.
我在我的一个应用程序中做了一些非常类似的事情,为了保持它的干净,我所做的就是让我的队列包含数据而不是要执行的线程。我使用一个 AsyncTask 来执行(它从系统分配的线程池中提取......可能会让您的管理更容易),并且在它的 doInBackground 方法中,我从队列中提取数据,对其进行操作,并在onPostExecute中再次调用我的入口方法。
I'm doing something very similar in one of my apps, and what I do to keep it clean is to make my queue contain the data and not the threads to execute. I use a single AsyncTask for my execution (which pulls from a thread pool that the system allocates...might make mgmt easier for you), and in the doInBackground method of it, I pull data out of the queue, operate on it, and call my entry method again in onPostExecute.
不需要自己构建它,只需使用 ThreadPoolExecutor 即可为你做。构建一个 minPool 大小为 1、最大池大小为 15 的池,您应该已准备就绪。
There's no need to build this yourself, just use a ThreadPoolExecutor to do it for you. construct one with a minPool size of 1, and a max pool size of 15, and you should be all set.
为什么不使用 Queue 而不是 ArrayList?它更适合这里。
Why don't you use a Queue instead of ArrayLists? It would fit in here better.
ArrayList 不是线程安全的,但您将它与线程一起使用。因此,不同的线程会互相妨碍。以下是可能发生的情况:
您使用各种可运行对象多次调用推送。所有这些方法都会同时调用 add 方法,但由于 add 不是线程安全的,因此第一个方法在第二个方法开始添加之前尚未完成添加,因此最终队列中只会有一个可运行对象。
然后 StartNext 会被同时调用很多次。其中一个线程运行“next =queue.Get()”,但是,在第一个线程有机会从队列中删除该项目之前,另一个线程也会调用“next=queue.Get()”,因此两个线程最终都会处理
您需要找到一个要使用的线程安全对象,或者添加某种类型的互斥/锁定机制以确保各个线程不会互相妨碍。
ArrayList is not thread safe, but you're using it with threading. As such, you have different threads getting in each others way. Here's what's probably happening:
You call push several times with various runnables. The add method gets called somewhat simultaneously for all of these, but because add is not thread safe, the first one doesn't finish adding before the second one starts adding, so you only end up with one runnable in your queue.
Then StartNext is called a bunch of times simultaneously. One of the threads runs "next = queue.Get(), however, another thread also calls "next = queue.Get()" before the first thread has a chance to remove that item from the queue, so both threads end up processing the same runnable.
You will need to either find a threadsafe object to use, or add some type of mutex/locking mechanism to ensure that the various threads don't get in each other's way.