2013-07-17 65 views
2
for (final ArrayList<SmartPhone> smartPhones : smartPhonesCluster) { 
    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      for (SmartPhone smartPhone : smartPhones) { 
       Queue<SmartPhoneTask> tasks = smartPhone.getSystem() 
                 .getTaskQue(); 
       SmartPhoneTask task = null; 
       assert tasks != null; 
       try { 
        while (!tasks.isEmpty()) { 
         task = tasks.poll(); // This is the line throwing the exception (GlobalNetwork.java:118) 
         assert task != null; 
         task.execute(); 
         task.onTaskComplete(); 
        } 
       } catch (RuntimeException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    }).start(); 
} 

並登錄後:NoSuchElementException異常甚至檢查

java.util.NoSuchElementException 
    at java.util.LinkedList.remove(LinkedList.java:788) 
    at java.util.LinkedList.removeFirst(LinkedList.java:134) 
    at java.util.LinkedList.poll(LinkedList.java:470) 
    at com.wtsang02.reu.botnet.network.GlobalNetwork$1.run(GlobalNetwork.java:118) 
    at java.lang.Thread.run(Thread.java:662) 
java.lang.NullPointerException 
Exception in thread "Thread-299" java.lang.AssertionError 
    at com.wtsang02.reu.botnet.network.GlobalNetwork$1.run(GlobalNetwork.java:119) 
    at java.lang.Thread.run(Thread.java:662) 

線118分:

task=tasks.poll(); 

如何解決這個問題?隊列是LinkedList的實現,如果這有所作爲。

+0

此方法被聲明爲synchronized。是的。 – wtsang02

+0

多個智能手機實例是否可以擁有相同的隊列?或者每個隊列都是「智能手機」實例獨有的? –

+0

每個隊列都是在每個智能手機的構造函數中創建的,每個智能手機都是唯一的。 – wtsang02

回答

7

LinkedList不是線程安全的,因此如果您在多個線程上訪問Linkedlist,則需要外部同步。這種同步在某個對象上(​​方法只是簡寫爲「在this上同步」),並且get和puts都必須在相同的對象上同步。你肯定是在這裏做的,因爲你爲每個SmartPhone創建一個新的線程,然後從那裏訪問該手機的LinkedList

如果一個線程付諸名單,而在someObject1同步,然後另一個線程讀取列表,而在someObject2同步,那麼這確實算作外部同步 - 代碼仍然是斷開的。

即使您使用了線程安全集合,如果多個線程同時清空隊列,也可能會觸發此異常。例如,想象一下:

thread A: put e into queue1 
thread B: queue1.isEmpty()? No, so go on 
thread C: queue1.isEmpty()? No, so go on 
thread B: queue1.poll() // works 
thread C: queue1.poll() // NoSuchElementException 

你應該使用BlockingQueue,其poll()方法將返回null如果在列表中沒有更多的元素。繼續拉,直到你得到一個null,然後打破循環。

+0

它在評論中,但我應該補充問題。但是該方法被聲明爲同步的。 – wtsang02

+0

除非我錯誤地閱讀代碼,否則每個'LinkedList'只能被一個線程訪問,因爲'LinkedList'應該是它自己的'SmartPhone'唯一的,並且每個線程都有一個唯一的'SmartPhone'。 –

+1

@ wtsang02如果該方法是無關緊要的,因爲在該方法中,您將啓動一個新線程,並且該線程的「run」方法不同步。即使是這樣,它也不會將任何東西放入元素中。請記住,同步總是在某個監視器上完成的,並且puts和gets(包括'isEmpty')需要在_same_監視器上同步。 – yshavit

相關問題