2017-08-12 67 views
3

如果我有一個線程敏感的名單,我通常是這樣的,而遍歷它:我必須在由流讀取的列表上同步嗎?

List list = Collections.synchronizedList(new ArrayList()); 
... 
synchronized(list) { 
    Iterator i = list.iterator(); // Must be in synchronized block 
    while (i.hasNext()) 
     foo(i.next()); 
} 

我不知道如果我使用list.stream(),並做一些,然後在操作像過濾器等的流,如果我還必須將列表放入同步塊中,還是將流列表複製到列表中?

感謝

回答

3

流操作使用方法spliterator()內部。

這裏是ArrayListspliterator()方法:

public Spliterator<E> spliterator() { 
     checkForComodification(); 
     return new ArrayListSpliterator<E>(ArrayList.this, offset, 
              offset + this.size, this.modCount); 
    } 

它檢查商品化,所以它看起來像stream()操作必須在你的情況在裏面synchronized塊。

而且,SynchronizedCollectionspliterator()(在Collections)具有評論

public Spliterator<E> spliterator() { 
     return c.spliterator(); // Must be manually synched by user! 
    } 

其類似於在iterator()註釋:

public Iterator<E> iterator() { 
     return c.iterator(); // Must be manually synched by user! 
    } 

其示出了相同的:同步圍繞stream()操作需要(至少,如果iterator()需要這樣的同步)。

而且最有說服力的:從SynchronizedCollectionstream()方法:

public Stream<E> stream() { 
     return c.stream(); // Must be manually synched by user! 
    } 
0

流可以被看作是對原始數據的「視圖」。這意味着:避免複製是其本質的一部分。

只有排序等操作需要創建輸入副本。因此:當你的輸入可以被另一個線程改變時 - 那麼你需要防止這一點。

0

是的,您必須同步訪問列表時使用流的方式與沒有流的方式相同。同步應該由用戶照顧。

流本身並不保證創建原始序列的任何副本。它可以在一些中間計算過程中複製(例如sort),但你不應該依賴它。對於流的每次使用,這樣做會浪費資源,因爲流are not reusable

例如,如果用戶想讓流操作於副本上,則必須手動創建副本或使用CopyOnWriteArrayList而不是ArrayList。請注意,streams are lazy。直到終端操作(例如,collect,forEach)被執行時才訪問基礎序列。

相關問題