2015-12-07 3 views
0

Я новичок в использовании ниток. В другом классе создается и запускается экземпляр класса ConnectionMaster (расширяет поток). Объект Client присваивается объекту ConnectionMaster, который добавляет его в список. Метод overridden run() класса Thread существенно прослушивает добавление клиента в список. Действительно, он прослушивает и «слышит», когда объект Client добавляется в список. Однако, хотя .hasNext() возвращает true .Next() вызывает исключение. Что я делаю не так?Исключение в теме "Thread-0" java.util.NoSuchElementException?

следующие методы из класса ConnectionMaster, который проходит Тема:

Конструктор

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

////////////////////////////// ОБНОВЛЕНИЕ ////////// ////////////////////////// Спасибо 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(); 
    } 

} 
+0

Теперь мой код работает. Спасибо. BlockingQueue - это то, что мне нужно. –

0

Что я делаю неправильно?

Довольно много на самом деле.

Первое, что вы делаете неправильно (видимо), используя объект ListIterator в нескольких потоках. Исполнения ListIterator и Iterator для Vector не являются потокобезопасными , поэтому то, что вы делаете, потенциально опасно.

Вторая вещь в том, что даже если итераторы/список итераторы были потокобезопасными, вы выполняете последовательность операций (например, hasNext, next, remove), не делая ничего, чтобы гарантировать, что последовательности операций выполняются таким образом, что это потокобезопасность. Существует четкая возможность того, что два потока могут выполнять одну и ту же последовательность одновременно на общем итераторе, и это может мешать другому.

Я не уверен, что предложить, чтобы исправить ваш код. Два потока, разделяющих итератор, не сработают.

Возможно, было бы лучше отбросить его и использовать какой-то Queue, как предложено @OldCurmugeon.


проблема либо 1, либо 2 проблема (как описано выше) может привести к NoSuchElement исключений.


1 - Это видно из рассмотрения исходного кода - http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/Vector.java#Vector.ListItr.