java.util.NoSuchElementException при запуске с семафором
У меня есть очередь, содержащая 10 элементов, и я запускаю 100 потоков, из которых 6 могут работать одновременно, управляя семафором. Когда работает каждый поток, он берет элемент head и добавляет его в хвост. Но иногда я получаю это исключение:
java.util.NoSuchElementException
at java.util.LinkedList.removeFirst(LinkedList.java:270)
at java.util.LinkedList.remove(LinkedList.java:685)
at IBM.SemApp$1.run(SemApp.java:27)
at java.lang.Thread.run(Thread.java:745)
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.Semaphore;
public class SemApp {
public static void main(String[] args) {
Queue queueB = new LinkedList<>();
for (int i = 0; i < 10; i++) {
queueB.add("Object " + i);
}
Runnable limitedCall = new Runnable() {
final Random rand = new Random();
final Semaphore available = new Semaphore(6);
int count = 0;
public void run() {
int time = rand.nextInt(15);
try {
available.acquire();
String A = (String) queueB.remove();
queueB.add(A);
available.release();
count++;
System.out.println(count);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
for (int i = 0; i < 100; i++) {
new Thread(limitedCall).start();
}
}
}
Что я делаю неправильно?
2 ответа
Проблема в том, что LinkedList
не является потокобезопасной структурой.
Следовательно, он не должен совместно использоваться и изменяться несколькими одновременными потоками, так как изменения в queueB
не может быть должным образом "передан" другим потокам.
Попробуйте использовать LinkedBlockingQueue
вместо.
Кроме того, используйте AtomicLong
за count
по той же причине: он распределяется между несколькими потоками, и вы хотите избежать условий гонки.
Тот факт, что до шести потоков могут работать в очереди одновременно, означает, что изменения не являются безопасными.