Java & Threads: прерванные исключения и как правильно использовать метод take () BlockingQueue
Что именно происходит, когда в очереди ничего нет и вызывается метод take(). API говорит, что метод будет ждать, но означает ли это, что процессор вращается, проверяя наличие пустого / не пустого, пока элемент не окажется в очереди, или это означает, что поток завершает работу и будет вызван прерыванием? Если это первый случай, я бы хотел посмотреть, пуста ли очередь и вызвана ли она thread.yield(), чтобы оставить процессорное время. Мой вопрос действительно должен ли я вызывать yield или какой-то внутренний механизм обрабатывает это для меня?
Во-вторых, для чего предназначено прерванное исключение? Если я правильно понимаю, это означает, что если поток A выполняет этот метод и ожидает ввода, а другой поток B вызывает threadA.interrupt(), то поток A будет перехватывать прерванное исключение и предположительно приостанавливать выполнение, если это хорошо. Это правильный способ думать об этом?
3 ответа
Обратите внимание, что BlockingQueue является интерфейсом. Итак, то, что следует, зависит от реализации. Если вы посмотрите на исходный код для (скажем) LinkedBlockingQueue, источник для take() вызывает lockInterruptibly() для RentrantLock. Из документа для этого:
Если блокировка недоступна, текущий поток отключается для целей планирования потоков и остается неактивным, пока не произойдет одно из двух:
* The lock is acquired by the current thread; or * Some other thread interrupts the current thread, and interruption of
получение блокировки поддерживается.
Я подозреваю, что будут некоторые wait()/notify()
или подобное происходит. Будет ли вращаться процессор? Нет (проверьте через top
или похожие)
Число рейнольдса на ваш вопрос о прерываниях, в бюллетене Java Specialist была очень интересная статья о interrupt()
и ловить / обрабатывать InterruptedException
,
Прочтите статью, но, по сути, если вы поймаете исключение, вы будете прерывать:
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt(); // very important
break;
}
Вызов wait() не вращается, обычно он использует службы ОС для ожидания события / условия - что переводит поток в спящий режим до тех пор, пока условие / событие не будет снова передано. Время ожидания процессора не используется.
Обычно вы получаете прерванное исключение, если поток блокирует вызов wait(), а другой поток вызывает interrupt() в этом блокирующем потоке, как вы и сказали.
Вызывать yield() считается плохой практикой, так как он не может обеспечить изящество - вы можете вызвать его, и планировщик мгновенно вернется в ваш поток, как если бы он не работал. Вместо этого используйте время ожидания (например, wait(1000)).
Прерывания - это безопасный способ сообщить нити, что вы хотите что-то от нее - прекратить обработку, проснуться и ответить на что-то и т. Д.
В целом, эти вещи зависят от ваших конкретных сценариев. В Java есть несколько приятных особенностей параллелизма, которые могут быть более применимы к ситуации.