2013-03-12 48 views
0

我想運行2個併發線程,其中一個向對象不斷添加對象,另一個更新這些對象,並且可能會從列表中刪除部分對象。 我有一個完整的項目,我用我的方法和類ArrayList,所以現在很難改變它。編輯ArrayList及其對象的多個線程

我環顧四周,發現了一些這樣做的方法,但正如我所說,它很難從ArrayList更改。我嘗試使用​​和notify()作爲將對象添加到列表的方法,並使用wait()更改這些對象的方法,如果它們符合特定條件,可能會將其刪除。

現在,我已經想出瞭如何使用CopyOnWriteArrayList來做到這一點,但我想知道是否有可能使用ArrayList本身來模擬此。所以我不必編輯我的整個代碼。

所以,基本上,我想這樣做,但ArrayList

import java.util.Iterator; 
import java.util.concurrent.CopyOnWriteArrayList; 

public class ListExample{ 
    CopyOnWriteArrayList<MyObject> syncList; 

    public ListExample(){ 
     syncList = new CopyOnWriteArrayList<MyObject>(); 

     Thread thread1 = new Thread(){ 
      public void run(){ 
       synchronized (syncList){ 
        for(int i = 0; i < 10; i++){ 
         syncList.add(new MyObject(i)); 
        } 
       } 
      } 
     }; 

     Thread thread2 = new Thread(){ 
      public void run(){ 
       synchronized (syncList){ 
        Iterator<MyObject> iterator = syncList.iterator(); 
        while(iterator.hasNext()){ 
         MyObject temp = iterator.next(); 

         //this is just a sample list manipulation 
         if (temp.getID() > 3) 
          syncList.remove(temp); 

         System.out.println("Object ID: " + temp.getID() + " AND list size: " + syncList.size()); 
        } 
       } 
      } 
     }; 

     thread1.start(); 
     thread2.start(); 
    } 

    public static void main(String[] args){ 
     new ListExample(); 
    } 
} 

class MyObject{ 
    private int ID; 

    public MyObject(int ID){ 
     this.ID = ID; 
    } 

    public int getID(){ 
     return ID; 
    } 

    public void setID(int ID){ 
     this.ID = ID; 
    } 
} 

我也看到了有關Collections.synchronizedList(new ArrayList())但同樣,我相信這將需要我改變我的代碼,我有大量的方法以ArrayList作爲參數。

任何指導將不勝感激,因爲我沒有想法。謝謝。

+5

重構早期重構通常是一種你會想要生存的口頭禪。現在更好地經歷痛苦,而不是稍後,更改代碼以使用接口'List'而不是具體實現'ArrayList'。 – Perception 2013-03-12 05:29:46

+1

就像一個筆記 - 你應該總是使用你需要功能的最低通用對象。如果你不需要'ArrayList'實際帶來的任何功能,你應該考慮使用'List'作爲你的方法參數。這將打開您的應用程序,擴展到更廣泛的實施基礎 - 只是一個想法 – MadProgrammer 2013-03-12 05:31:05

+0

您似乎在努力解決生產者 - 消費者問題。嘗試谷歌它解決生產者 - 消費者問題 – Sach 2013-03-12 05:34:30

回答

4

您可能會對java.util.concurrent軟件包提供的產品系列感興趣。它們對於生產者/消費者場景非常有用,其中一個或多個線程將某些內容添加到隊列中,其他線程將其添加到隊列中。根據是否要阻塞,有不同的方法,或者在隊列滿/空時失敗。

關於重構您的方法,您應該使用接口(例如List)而不是具體的實現類(如ArrayList)。這是接口的目的,並且Java API對它們有很好的支持。

+0

你可以命名TS應該使用的集合之一? – 2016-07-25 14:05:19

+0

某些實現是'ArrayBlockingQueue'和'LinkedBlockingDeque',請參閱http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html – Javier 2016-07-26 01:10:02

1

作爲一種快速解決方案,你可以擴展ArrayList並使修改方法(添加/刪除)同步。並重新分解代碼以將ArrayList替換爲您的自定義ArrayList

0

使用Vector而不是ArrayList。請記住將它存儲在List引用中,因爲Vector包含已棄用的方法。與ArrayList不同,Vector與其內部操作同步,而不像CopyOnWriteArrayList,每次修改時都不復制內部數組。

0

當然你應該使用java.util.concurrent pakage。但是讓我們看看只有ArrayList和同步發生了什麼/可能發生什麼。

在你的代碼,如果你剛纔ArrayList代替CopyOnWriteArrayList,爲您提供在任何你正在做的/在線程操作完全同步synchronized (syncList)它應該工作。如果整個事物是同步的,則不需要任何wait()notify()(但不建議這樣做)。

但這個代碼將會給ConcurrentModificationException因爲一旦你使用迭代器syncList.iterator()你不應該從列表中刪除元素,否則可能會產生不良的結果,而迭代這就是爲什麼它被設計用來快速失敗,並給予例外。爲了避免這種情況,你可以用這樣的:

   Iterator<MyObject> iterator = syncList.iterator(); 
       ArrayList<MyObject> toBeRemoved = new ArrayList<MyObject>(); 
       while(iterator.hasNext()){ 
        MyObject temp = iterator.next(); 

        //this is just a sample list manipulation 
        if (temp.getID() > 3) 
        { 
         //syncList.remove(temp); 
         toBeRemoved.add(temp); 
        } 
        System.out.println("Object ID: " + temp.getID() + " AND list size: " + syncList.size()); 
       } 
       syncList.removeAll(toBeRemoved); 

現在就同步,你要努力,否則儘量減少它的範圍就會有線程之間不必要的等待,這就是爲什麼java.util.concurrent包被賦予具有高性能在多線程中(甚至使用非阻塞算法)。或者您也可以使用Collections.synchronizedList(new ArrayList()),但它們不如concurrent類。

如果您想要像生產者/消費者問題那樣使用條件同步,那麼您可以在同一對象(鎖定)上使用wait()notify()機制。但是,現在已經有一些類可以幫助使用java.util.concurrent.LinkedBlockingQueue