3
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();
}

并记录:

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 实现,如果这有所作为。

4

1 回答 1

9

LinkedList不是线程安全的,因此如果您Linkedlist在多个线程上访问 a ,则需要外部同步。这种同步在某个对象上(synchronized方法只是“同步上this”的简写),gets 和 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

您应该使用,如果列表中没有更多元素,则BlockingQueuepoll()方法将返回。null继续拉直到你得到一个null,然后打破循环。

于 2013-07-17T17:05:44.983 回答