简体   繁体   English

线程“ Thread-0”中的异常java.util.NoSuchElementException?

[英]Exception in thread “Thread-0” java.util.NoSuchElementException?

I am new to using threads. 我是使用线程的新手。 In another class an instance of the ConnectionMaster class is created and started (extends thread). 在另一个类中,将创建并启动ConnectionMaster类的实例(扩展线程)。 A Client object is given to the ConnectionMaster object which adds it to the list. 将Client对象提供给ConnectionMaster对象,该对象将其添加到列表中。 The overridden run() method of the Thread class essentially listens for a client to be added to the list. Thread类的重写run()方法本质上侦听要添加到列表中的客户端。 Indeed it does listen and "hears" when a Client object is added to the list. 实际上,当将Client对象添加到列表时,它确实会监听并“听到”。 However, although .hasNext() returns true .Next() causes an exception. 但是,尽管.hasNext()返回true,但.Next()会导致异常。 What am I doing wrong? 我究竟做错了什么?

The following methods are from class ConnectionMaster which extends Thread: 以下方法来自扩展线程的ConnectionMaster类:

Constructor 建设者

public ConnectionMaster(){
    clients = new Vector<>();
    listIterator = clients.listIterator();
}

Public method for adding client objects to the list 用于将客户端对象添加到列表的公共方法

@Override
public synchronized void addClient(Client client) {
    listIterator.add(client);
}

This is the overridden thread method of the class Thread. 这是Thread类的重写线程方法。 It consistently checks for elements added to the list. 它始终检查添加到列表中的元素。

@Override
public void run(){
    while(true){
        while(listIterator.hasNext()){
            processClient(listIterator.next()); //this is where error occurs
            listIterator.remove();
        }

        while(listIterator.hasPrevious()){
            processClient(listIterator.previous());
            listIterator.remove();
        }
    }
}

////////////////////////////////UPDATE//////////////////////////////////// Thank You OldCurmudgeon and Stephen C. Based on your feedback, my code has been modified thus: /////////////////////////////// UPDATE //////////////////// /////////////////谢谢OldCurmudgeon和StephenC。根据您的反馈,我的代码已被修改,因此:

Constructor 建设者

public ConnectionMaster(){
    clients = new ArrayBlockingQueue<Client>(1024);
}

Method for receiving client objects 接收客户端对象的方法

@Override
public synchronized void addClient(Client client) {
    try {
        clients.put(client);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

Listener 听众

@Override
public void run(){
    while(true){
        try {
            processClient((Client)clients.take());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

This is a very strange way to implement Producer/Consumer. 这是实现生产者/消费者的非常奇怪的方式。 The usual way is to use a BlockingQueue . 通常的方法是使用BlockingQueue

public class TwoThreads {

    public static void main(String args[]) throws InterruptedException {
        System.out.println("TwoThreads:Test");
        new TwoThreads().test();
    }

    // The end of the list.
    private static final Integer End = -1;

    static class Producer implements Runnable {

        final BlockingQueue<Integer> queue;

        public Producer(BlockingQueue<Integer> queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            try {
                for (int i = 0; i < 1000; i++) {
                    queue.add(i);
                    Thread.sleep(1);
                }
                // Finish the queue.
                queue.add(End);
            } catch (InterruptedException ex) {
                // Just exit.
            }
        }

    }

    static class Consumer implements Runnable {

        final BlockingQueue<Integer> queue;

        public Consumer(BlockingQueue<Integer> queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            boolean ended = false;
            while (!ended) {
                try {
                    Integer i = queue.take();
                    ended = i == End;
                    System.out.println(i);
                } catch (InterruptedException ex) {
                    ended = true;
                }
            }
        }

    }

    public void test() throws InterruptedException {
        BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
        Thread pt = new Thread(new Producer(queue));
        Thread ct = new Thread(new Consumer(queue));
        // Start it all going.
        pt.start();
        ct.start();
        // Wait for it to finish.
        pt.join();
        ct.join();
    }

}

What am I doing wrong? 我究竟做错了什么?

Quite a lot actually. 实际上很多。

First thing you are doing wrong is (apparently) using an ListIterator object in multiple threads. 您做错的第一件事是(显然)在多个线程中使用ListIterator对象。 The ListIterator and Iterator implementations for Vector are not thread-safe 1 , so what you are doing is potentially hazardous. VectorListIteratorIterator实现不是线程安全的1 ,因此您正在做的事情有潜在的危险。

The second thing is that even if the iterators / list iterators were thread-safe, you are performing a sequence of operations (eg hasNext , next , remove ) without doing anything to ensure that the sequence of operations is performed in a way that is threadsafe. 第二件事是,即使迭代器/列表迭代器是线程安全的,您也将执行一系列操作(例如hasNextnextremove ),而无需执行任何操作以确保以线程安全的方式执行操作序列 There is a distinct possibility that two threads could be performing the same sequence simultaneously on the shared iterator, and that one could interfere with the other. 两个线程可能在共享的迭代器上同时执行相同的序列,并且一个线程可能干扰另一个线程,这是很可能的。

I'm not sure what to suggest in order to fix your code. 我不确定建议如何修改您的代码。 Two threads sharing an iterator is not going to work. 共享一个迭代器的两个线程将无法工作。

It would probably be better to ditch it, and use some kind of Queue as suggested by @OldCurmugeon. 最好放弃它,并使用@OldCurmugeon建议的某种Queue


Either problem 1 or problem 2 (as outlined above) could give rise to NoSuchElement exceptions. 问题1或问题2(如上所述)都可能导致NoSuchElement异常。


1 - This is apparent from examining the source code - http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/Vector.java#Vector.ListItr . 1-从检查源代码可以明显看出这一点-http: //grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/Vector.java#Vector.ListItr

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM