2012-05-07 47 views
0

從線程列表中刪除節點的線程安全方法。如何提高以下java方法從鏈表中刪除元素的性能

public void delete(String x, LinkedList<String> list) 
    { 
     String lock = "false"; 
     for (int i = 0; i < list.size(); i++) { 
      synchronized (lock) { 
       if (list.get(i).equals(x)) { 
        lock = "true"; 
        list.remove(i); 
       } 
       lock = "false"; 
      } 
     } 
    } 

非常感謝!

編輯:上述方法是線程安全的,但其性能需要改進。這是一個面試問題。

+1

,這可能是更適合於[代碼審查](http://codereview.stackexchange.com/) –

+3

內部*循環絕對不能進入同步塊*。這同時對性能**和**線程不安全是不利的。 –

+1

這是真的關於多個線程還是你得到一個異常,因爲你正在從列表中刪除而迭代呢? – Gray

回答

3
  1. 在方法本地的對象上同步實際上並沒有什麼用處。此外,覆蓋對鎖定在同步塊內的對象的引用會造成混淆。關於該代碼的目的的一些解釋可能會幫助我們幫助您改進它:)

  2. 實際的問題。 get(i)remove(i)都要求您將列表迭代到位置i。如果使用列表的實際迭代器和迭代器的remove方法,則只需迭代整個列表一次。

2

線程安全:

public void delete(String x, LinkedList<String> list) { 
    synchronized (list) { 
     for (Iterator<String> it = list.iterator(); it.hasNext();) 
      if (it.next().equals(x)) it.remove(); 
    } 
} 

但是,在所有的可能性,你的問題不是線程安全的。您在遍歷列表時使用了list.delete(),並獲得ConcurrentModificationException。如果是這種情況,請隨時刪除同步塊。

+0

只有當列表中的每個操作都通過任何類的相同實例執行此方法時才進行排序。 – Affe

+0

@Affe更正。 –

+0

嘗試了你的方法,但它似乎只是第一個線程真的在做這項工作。每個其他的線程都被同步阻止(列表) – Bobo

0

嘗試使用開箱即用的Java Collections API功能進行同步收集。 Official documentation.

而且你也可以使用迭代器來刪除項目。如文檔所述:

如果使用顯式迭代器,則必須從synchronized塊中調用迭代器方法 。不遵循此建議可能導致不確定的行爲 。

1

我會用List.removeAll

List<String> list = new LinkedList<>(); 
list.addAll(Arrays.asList("a,b,c,d,a,b,c,d,e,a,b,a,b".split(","))); 
System.out.println("Before removeAll(a) " + list); 

list.removeAll(Collections.singleton("a")); 

System.out.println("After removeAll " +list); 

打印

Before removeAll(a) [a, b, c, d, a, b, c, d, e, a, b, a, b] 
After removeAll [b, c, d, b, c, d, e, b, b] 
0
public void delete (String x, LinkedList<String> list) { 

      synchronized (list) { 
       Iterator<String> it = list.iterator(); 
       while (it.hasNext()) { 
        String y = it.next(); 
        if (x.equals(y)) { 
         it.remove(); 
        } 
       } 
      } 
     } 
0
public void delete(String x, LinkedList<String> list){ 
    Set<String> target = Collections.singleton(x); 
    synchronized (list) { 
     list.removeAll(target); 
    } 
} 

兩件事情:

  1. 在剛剛創建的字符串上進行同步不會產生任何效果(嗯,不完全一樣,因爲"false"是一個interned字符串,所以在"false"上同步的所有代碼片段都將被同步,但這是一種用於獲得應用程序範圍內同步的駭客辦法,可能不會根據你的意圖)。你應該在列表上同步。每個使用列表的人都應該在列表中進行同步。雖然更好的做法是首先使用同步收集,但不需要在使用的代碼中明確使用​​塊。
  2. removeAll通常是從集合中刪除所有出現的一個或多個對象的最有效的方法。在最糟糕的情況下,它相當於遍歷集合並使用迭代器刪除項目(這是LinkedList的情況),但對於某些實現(如ArrayList),它變得更高效。