Неужели плохо использовать опрос в Java?
У меня есть несколько ArrayLists
, которые работают как очереди данных. Каждая из очередей связана с отдельным потоком, который проверяет, имеет ли этот ArrayList
некоторые данные в нем.
while (array.size == 0) {
// nothing
}
// do stuff with one element of the array
// remove element from array
// and call the loop again
Я сделал аналогичные вещи во встроенном системном программировании, но безопасно ли это использовать в Java? Забота об отходах технологической мощности, итерации вокруг этого, в то время как цикл очень быстрый.
Это можно решить, добавив Thread.sleep(100)
и проверить каждые 100 мс, а затем снова - более медленное время отклика.
Вопрос: мне нужно добавить этот сон, или я не должен беспокоиться об этом?
Любые предложения по более безопасной/лучшей системе для проверки новых данных в массивах?
Ответы
Ответ 1
ArrayList не является потокобезопасной коллекцией, поэтому, если один поток добавляет данные в ваш список, а другой поток пытается извлечь данные из одного и того же списка, у вас нет гарантии, что другой поток когда-либо увидит добавленные элементы.
И ожидание, как вы описываете, потребляет ресурсы процессора без необходимости.
Поскольку вам, похоже, нужна очередь, почему бы вам не использовать ее, например ArrayBlockingQueue
. Он имеет take
метод, который блокирует, не потребляя циклы процессора, до тех пор, пока элемент не будет добавлен в очередь. И это потокобезопасно.
Ответ 2
Если время, которое вам нужно подождать, очень короткое, что делает слишком сложным переключение контекста, я бы не использовал прядение. Он определенно тратит процессорные циклы без уважительной причины.
Вы должны использовать wait/notify
или какой-либо другой механизм сигнализации для приостановки потока и разбудить его только при необходимости.
Переходя к более продвинутым конструкциям, существуют специализированные структуры данных для моделей-производителей-потребителей, например BlockingQueue (выберите реализацию):
Очередь, которая дополнительно поддерживает операции, ожидающие очереди стать непустым при извлечении элемента и дождаться места становятся доступными в очереди при хранении элемента.
Ответ 3
Как насчет использования somehting как блокирующей очереди, которая была выпущена в java 5. Я думаю, что это рекомендуется сейчас по wait/notify, которое может стать довольно сложным. Я использовал его, и он работает хорошо.
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html
Ответ 4
java.lang.ArrayList
не является потокобезопасным вообще. Для целей массового обслуживания полезно использовать BlockingQueue
. Он блокирует вызов потока, если очередь пуста, не потребляя процессор. Вы можете использовать ArrayBlockingQueue
или LinkedBlockingQueue
или другую реализацию очереди в соответствии с вашими потребностями.
Даже вы можете реализовать его с помощью wait and notifyAll
, но всегда рекомендуется использовать BlockingQueue
.
Ответ 5
Вместо использования ArrayList вы можете использовать коллекцию Concurrent, скажем, например, ArrayBlockingQueue
ArrayBlockingQueue<YourObject> theQueue;
while(true) {
YourObject o = theQueue.take();
//process your object
}
В другом месте, где вы заполняете свою очередь, вы просто выполняете
theQueue.add(theElement);
Поток, ожидающий объекты, будет "спать" до тех пор, пока не появится элемент. Метод add пробудит поток потребления.
Подробнее об этом классе читайте здесь: http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ArrayBlockingQueue.html
Ответ 6
Без сна ваши потоки будут работать так же быстро, как они могут, и получить доступ к ArrayList, возможно, в большинстве случаев без каких-либо результатов.
Я бы рекомендовал реализовать шаблон прослушивателя/наблюдателя. Если возможно, попросите продюсера, который заполняет ArrayList, уведомляет соответствующие потоки об изменениях. Таким образом, вы переключитесь с поведения опроса на поведение push.
Не уверен, что это выполнимо в вашей архитектуре, вам потребуются дополнительные объяснения в вашей системе.
Ответ 7
Что такое опрос и какие проблемы с ним?
Процесс проверки состояния повторно до тех пор, пока он не станет истинным, известен как опрос.
Опрос обычно выполняется с помощью циклов, чтобы проверить, является ли конкретное условие истинным или нет. Если это так, то предпринимаются определенные действия. Этот отход многих циклов процессора и делает реализацию неэффективной.
Например, в классической задаче массового обслуживания, когда один поток создает данные, а другой потребляет его.
Как многопоточная многопоточность Java решает эту проблему?
Чтобы избежать опроса, Java использует три метода: wait()
, notify()
и notifyAll()
.
Все эти методы относятся к классу Object
как final, так что все классы имеют их. Они должны использоваться только в синхронизированном блоке.
wait(). Он сообщает вызывающему потоку отказаться от блокировки и перейдет в режим сна, пока какой-либо другой поток не войдет в тот же монитор и не вызовет notify()
.
notify(). Пробуждает один единственный поток, который называется wait()
на том же самом объекте. Следует отметить, что вызов notify()
фактически не отменяет блокировку ресурса.
notifyAll() - он просыпает все потоки, которые вызывали wait()
на одном и том же объекте.
ArrayList
не является потокобезопасной коллекцией. Используйте ArrayBlockingQueue
.
Класс ArrayBlockingQueue