2011-09-14 50 views
4

我試圖在異步任務期間一個接一個地執行runnable隊列(意味着隊列中的下一個將在另一個完成後執行)。我編寫了一個管理器來管理這些可自行運行的runnable和task。然後我在異步任務中獲得第一個任務並運行它,希望它能夠通過隊列運行,但是它只是最終運行第一個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); 
    } 

回答

2

我在我的一個應用程序中做了非常類似的事情,我做的保持乾淨的是讓我的隊列包含數據而不是要執行的線程。我爲我的執行使用了一個AsyncTask(從系統分配的線程池中提取...可能會讓管理更容易),並且在它的doInBackground方法中,我將數據從隊列中提取出來,對其進行操作,並在onPostExecute中再次調用我的入口方法。

2

有沒有必要自己建立這個,只需使用ThreadPoolExecutor爲你做。構建一個minPool大小爲1,最大池大小爲15的應用程序,並且應該全部設置。

+0

如果可運行對象累計超過十億,會發生什麼? – User3

2

爲什麼不使用Queue而不是ArrayLists?它會更適合在這裏。

1

ArrayList不是線程安全的,但是您將它與線程一起使用。因此,你有不同的線程進入其他方式。以下是可能發生的事情:

  • 您使用各種可運行的程序調用多次推送。對於所有這些,add方法都會被同時調用,但由於add不是線程安全的,第一個在第二個開始添加之前沒有完成添加,所以最終只有一個可以在隊列中運行。

  • 然後StartNext被同時調用一堆。其中一個線程運行「next = queue.Get(),但是,另一個線程在第一個線程有機會從隊列中刪除該項目之前,還會調用」next = queue.Get()「,這樣兩個線程最終都會處理同樣可運行。

你需要找到一條線程對象來使用,或增加一些類型的互斥鎖/鎖機制,以確保各線程不會在對方的方式獲得。