我是新手使用线程。在另一个类中,创建并启动ConnectionMaster类的实例(扩展线程)。 Client对象被赋予ConnectionMaster对象,该对象将其添加到列表中。 Thread类的重写run()方法实质上是侦听要添加到列表的客户端。实际上,当客户端对象添加到列表中时,它会侦听并“听到”。但是,尽管.hasNext()返回true .Next()会导致异常。我做错了什么?
以下方法来自ConnectionMaster类,它扩展了Thread:
构造
public ConnectionMaster(){
clients = new Vector<>();
listIterator = clients.listIterator();
}
将客户端对象添加到列表的公共方法
@Override
public synchronized void addClient(Client client) {
listIterator.add(client);
}
这是Thread类的重写线程方法。它始终检查添加到列表中的元素。
@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 ////////////// ////////////////////// 谢谢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();
}
}
}
答案 0 :(得分:1)
这是实现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();
}
}
答案 1 :(得分:0)
我做错了什么?
实际上很多。
你做错的第一件事是(显然)在多个线程中使用ListIterator
对象。 ListIterator
的{{1}}和Iterator
实现不是线程安全的 1 ,因此您正在做的事情具有潜在的危险性。
第二件事是,即使迭代器/列表迭代器是线程安全的,你也在执行一系列操作(例如Vector
,hasNext
,next
)而不做任何事情确保以线程安全的方式执行操作的序列。两个线程可能在共享迭代器上同时执行相同的序列,而另一个线程可能会干扰另一个线程。
我不确定要修改代码的建议。共享迭代器的两个线程不起作用。
放弃它可能会更好,并按照@OldCurmugeon的建议使用某种remove
。
问题1或问题2(如上所述)可能会导致Queue
例外。
1 - 通过检查源代码 - http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/Vector.java#Vector.ListItr可以明显看出这一点。功能