Вопросы:Как предотвратить, чтобы мои потребительские потоки дважды удаляли последний элемент?
- Почему я получаю NoSuchElementException при попытке удалить последний элемент ?
- Как это исправить?
У меня есть 3-х классов (смотри ниже), что добавить/удалить типа Integer к LinkedList. Все работает нормально до тех пор, пока не удалятся нитки до последнего элемента.
Кажется, что обе нити пытаются его удалить. Первый преуспевает, второй не может. Но я думал, что этот синхронный метод/синхронизированный атрибут + !sharedList.isEmpty()
справится с этим.
Class Производитель: Этот класс должен созданных случайных чисел, положить их в sharedList, писать в консоль, что он просто добавил номер и остановиться, как только она будет прервана. Ожидается только 1 поток этого класса.
import java.util.LinkedList;
public class Producer extends Thread
{
private LinkedList sharedList;
private String name;
public Producer(String name, LinkedList sharedList)
{
this.name = name;
this.sharedList = sharedList;
}
public void run()
{
while(!this.isInterrupted())
{
while(sharedList.size() < 100)
{
if(this.isInterrupted())
{
break;
} else
{
addElementToList();
}
}
}
}
private synchronized void addElementToList()
{
synchronized(sharedList)
{
sharedList.add((int)(Math.random()*100));
System.out.println("Thread " + this.name + ": " + sharedList.getLast() + " added");
}
try {
sleep(300);
} catch (InterruptedException e) {
this.interrupt();
}
}
}
Класс Потребитель: Этот класс должен удалить первый элемент в sharedList, если он существует. Выполнение должно продолжаться (после прерывания) до sharedList пуст. Ожидается несколько (по крайней мере 2) потоков этого класса.
import java.util.LinkedList;
public class Consumer extends Thread
{
private String name;
private LinkedList sharedList;
public Consumer(String name, LinkedList sharedList)
{
this.name = name;
this.sharedList = sharedList;
}
public void run()
{
while(!this.isInterrupted())
{
while(!sharedList.isEmpty())
{
removeListElement();
}
}
}
private synchronized void removeListElement()
{
synchronized(sharedList)
{
int removedItem = (Integer) (sharedList.element());
sharedList.remove();
System.out.println("Thread " + this.name + ": " + removedItem + " removed");
}
try {
sleep(1000);
} catch (InterruptedException e) {
this.interrupt();
}
}
}
Класс MainMethod: Этот класс должен начинать и прерывать нити.
import java.util.LinkedList;
public class MainMethod
{
public static void main(String[] args) throws InterruptedException
{
LinkedList sharedList = new LinkedList();
Producer producer = new Producer("producer", sharedList);
producer.start();
Thread.sleep(1000);
Consumer consumer1 = new Consumer("consumer1", sharedList);
Consumer consumer2 = new Consumer("consumer2", sharedList);
consumer1.start();
consumer2.start();
Thread.sleep(10000);
producer.interrupt();
consumer1.interrupt();
consumer2.interrupt();
}
}
Исключение: Это точное исключение я получаю.
Исключение в потоке "Резьба-2" java.util.NoSuchElementException на java.util.LinkedList.getFirst (LinkedList.java:126) в java.util.LinkedList.element (LinkedList.java:476) в Consumer.removeListElement (Consumer.java:29) в Consumer.run (Consumer.java:20)
Почему бы не использовать ['BlockingQueue'] (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html) для проблем с потоковыми производителями? – zapl
Почему два цикла? может у, пожалуйста, объясните мне? –
@VishalSanthrama Я думал, что 2 петли необходимы для a) не останавливаться до прерывания (внешний цикл) и b) даже если прерывание не останавливается до тех пор, пока List не будет пустым (внутренний цикл). Если я ошибаюсь. – whateverrest