线程 "Thread-0" java.util.NoSuchElementException 中出现异常?
Exception in thread "Thread-0" java.util.NoSuchElementException?
我是线程的新手。在另一个 class 中创建并启动了 ConnectionMaster class 的实例(扩展线程)。将 Client 对象提供给 ConnectionMaster 对象,后者将其添加到列表中。 Thread class 的重写 运行() 方法本质上是监听要添加到列表中的客户端。实际上,当将 Client 对象添加到列表时,它确实会监听并 "hears" 。但是,尽管 .hasNext() returns true .Next() 会导致异常。我做错了什么?
以下方法来自 class ConnectionMaster 扩展 Thread:
构造函数
public ConnectionMaster(){
clients = new Vector<>();
listIterator = clients.listIterator();
}
Public 将客户端对象添加到列表的方法
@Override
public synchronized void addClient(Client client) {
listIterator.add(client);
}
这是 class 线程的覆盖线程方法。它始终检查添加到列表中的元素。
@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();
}
}
}
/////////////////////////////更新//////////// ////////////////////////
谢谢 OldCurmudgeon 和 Stephen C.
根据您的反馈,我的代码已修改为:
构造函数
public ConnectionMaster(){
clients = new ArrayBlockingQueue<Client>(1024);
}
接收客户端对象的方法
@Override
public synchronized void addClient(Client client) {
try {
clients.put(client);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
听众
@Override
public void run(){
while(true){
try {
processClient((Client)clients.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
这是一种非常奇怪的实现方式Producer/Consumer。通常的方法是使用 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?
实际上很多。
您做错的第一件事是(显然)在多个线程中使用 ListIterator
对象。 Vector
的 ListIterator
和 Iterator
实现不是线程安全的1,因此您正在做的事情有潜在危险。
第二件事是,即使迭代器/列表迭代器是线程安全的,您正在执行一系列操作(例如 hasNext
、next
、remove
)而不做任何事情来确保 sequence 操作以线程安全的方式执行。两个线程可能同时在共享迭代器上执行相同的序列,并且一个线程可能会干扰另一个线程,这是一种明显的可能性。
我不确定要修复您的代码有什么建议。两个线程共享一个迭代器是行不通的。
最好放弃它,并按照@OldCurmugeon 的建议使用某种 Queue
。
问题 1 或问题 2(如上所述)都可能导致 NoSuchElement
异常。
1 - 通过检查源代码可以明显看出这一点 - http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/Vector.java#Vector.ListItr。
我是线程的新手。在另一个 class 中创建并启动了 ConnectionMaster class 的实例(扩展线程)。将 Client 对象提供给 ConnectionMaster 对象,后者将其添加到列表中。 Thread class 的重写 运行() 方法本质上是监听要添加到列表中的客户端。实际上,当将 Client 对象添加到列表时,它确实会监听并 "hears" 。但是,尽管 .hasNext() returns true .Next() 会导致异常。我做错了什么?
以下方法来自 class ConnectionMaster 扩展 Thread:
构造函数
public ConnectionMaster(){
clients = new Vector<>();
listIterator = clients.listIterator();
}
Public 将客户端对象添加到列表的方法
@Override
public synchronized void addClient(Client client) {
listIterator.add(client);
}
这是 class 线程的覆盖线程方法。它始终检查添加到列表中的元素。
@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();
}
}
}
/////////////////////////////更新//////////// //////////////////////// 谢谢 OldCurmudgeon 和 Stephen C. 根据您的反馈,我的代码已修改为:
构造函数
public ConnectionMaster(){
clients = new ArrayBlockingQueue<Client>(1024);
}
接收客户端对象的方法
@Override
public synchronized void addClient(Client client) {
try {
clients.put(client);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
听众
@Override
public void run(){
while(true){
try {
processClient((Client)clients.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
这是一种非常奇怪的实现方式Producer/Consumer。通常的方法是使用 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?
实际上很多。
您做错的第一件事是(显然)在多个线程中使用 ListIterator
对象。 Vector
的 ListIterator
和 Iterator
实现不是线程安全的1,因此您正在做的事情有潜在危险。
第二件事是,即使迭代器/列表迭代器是线程安全的,您正在执行一系列操作(例如 hasNext
、next
、remove
)而不做任何事情来确保 sequence 操作以线程安全的方式执行。两个线程可能同时在共享迭代器上执行相同的序列,并且一个线程可能会干扰另一个线程,这是一种明显的可能性。
我不确定要修复您的代码有什么建议。两个线程共享一个迭代器是行不通的。
最好放弃它,并按照@OldCurmugeon 的建议使用某种 Queue
。
问题 1 或问题 2(如上所述)都可能导致 NoSuchElement
异常。
1 - 通过检查源代码可以明显看出这一点 - http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/Vector.java#Vector.ListItr。