|
Spec-Zone .ru
спецификации, руководства, описания, API
|
Thread.stop осуждаемый?Поскольку это по сути опасно. Остановка потока заставляет это разблокировать все мониторы, которые это заблокировало. (Мониторы разблокированы как ThreadDeath исключение распространяет стек.), Если какой-либо из объектов, ранее защищенных этими мониторами, был в непоследовательном состоянии, другие потоки могут теперь просмотреть эти объекты в непоследовательном состоянии. Такие объекты, как говорят, повреждаются. Когда потоки работают на поврежденных объектах, произвольное поведение может закончиться. Это поведение может быть тонким и трудным обнаружить, или это может быть объявлено. В отличие от других исключений непроверенных, ThreadDeath уничтожает потоки тихо; таким образом у пользователя нет никакого предупреждения, что его программа может быть повреждена. Повреждение может проявиться в любое время после того, как фактическое повреждение происходит, даже часы или дни в будущем.
ThreadDeath исключение и фиксирует поврежденный объект?В теории, возможно, но это значительно усложнило бы задачу записи корректного многопоточного кода. Задача была бы почти непреодолима по двум причинам:
ThreadDeath исключение почти где угодно. Все синхронизируемые методы и блоки должны были бы быть изучены очень подробно с этим в памяти.ThreadDeath исключение, очищая сначала (в catch или finally пункт). Уборка имела бы к повторному, пока она не успешно выполнялась. Код, чтобы гарантировать это был бы довольно сложен.Thread.stop(Throwable)?В дополнение ко всем проблемам, отмеченным выше, этот метод может использоваться, чтобы генерировать исключения, которые его целевой поток неподготовлен, чтобы обработать (включая проверенные исключения, которые не мог возможно выдать поток, было это не для этого метода). Например, следующий метод поведенчески идентичен Java throw работа, но обходит попытки компилятора гарантировать, что метод вызова объявил все проверенные исключения, которые это может выдать:
static void sneakyThrow(Throwable t) {
Thread.currentThread().stop(t);
}
Thread.stop?Большинство использования stop должен быть заменен кодом, который просто изменяет некоторую переменную, чтобы указать, что целевой поток должен прекратить работать. Целевой поток должен регулярно проверять эту переменную, и возврат из его метода выполнения аккуратным способом, если переменная указывает, что это должно прекратить работать. Чтобы гарантировать быструю передачу запроса остановки, переменной должен быть volatile (или доступ к переменной должен синхронизироваться).
Например, предположите, что Ваш апплет содержит следующий start, stop и run методы:
private Thread blinker;
public void start() {
blinker = new Thread(this);
blinker.start();
}
public void stop() {
blinker.stop(); // UNSAFE!
}
public void run() {
while (true) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
}
repaint();
}
}
Можно избежать использования Thread.stop заменяя апплет stop и run методы с:
private volatile Thread blinker;
public void stop() {
blinker = null;
}
public void run() {
Thread thisThread = Thread.currentThread();
while (blinker == thisThread) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
}
repaint();
}
}
Это что Thread.interrupt метод для. То же самое "состояние базируемый" сигнальный механизм, показанный выше, может использоваться, но изменение состояния (blinker = null, в предыдущем примере), может сопровождаться звонком Thread.interrupt, прерывать ожидание:
public void stop() {
Thread moribund = waiter;
waiter = null;
moribund.interrupt();
}
Для этого метода, чтобы работать, является критическим, что любой метод, который ловит исключение прерывания и не готовится иметь дело с ним сразу, подтверждает исключение. Мы говорим, подтверждает, а не повторно бросает, потому что не всегда возможно повторно бросить исключение. Если метод, который ловит InterruptedException как объявляют, не выдает это (проверенное) исключение, тогда оно должно "повторно прервать себя" следующим колдовством:
Thread.currentThread().interrupt();
Это гарантирует, что Поток повторно повысит InterruptedException как только это в состоянии. Thread.interrupt?В некоторых случаях можно использовать специализированные приемы. Например, если поток ожидает на известном сокете, можно закрыть сокет, чтобы заставить поток сразу возвратиться. К сожалению, действительно нет никакого метода, который работает вообще. Нужно отметить, что во всех ситуациях, где поток ожидания не отвечает на Thread.interrupt, это не ответило бы на Thread.stop также. Такие случаи включают преднамеренные атаки "отказ в обслуживании", и операции ввода-вывода, на которые thread.stop и thread.interrupt не работают должным образом.
Thread.suspend и Thread.resume осуждаемый?Thread.suspend является по сути склонным к мертвой блокировке. Если целевой поток содержит блокировку на мониторе, защищающем критический системный ресурс, когда это приостанавливается, никакой поток не может получить доступ к этому ресурсу, пока целевой поток не возобновляется. Если поток, который возобновил бы целевой поток, пытается заблокировать этот монитор до вызова resume, результаты мертвой блокировки. Такие мертвые блокировки обычно проявляются как "замороженные" процессы.
Thread.suspend и Thread.resume?Как с Thread.stop, у благоразумного подхода должен быть "целевой поток", опрашивают переменную, указывающую на требуемое состояние потока (активный или приостановленный). Когда требуемое состояние приостанавливается, поток ожидает, используя Object.wait. Когда поток возобновляется, целевой поток уведомляется, используя Object.notify.
Например, предположите, что Ваш апплет содержит следующий mousePressed обработчик событий, который переключает состояние вызванного потока blinker:
private boolean threadSuspended;
Public void mousePressed(MouseEvent e) {
e.consume();
if (threadSuspended)
blinker.resume();
else
blinker.suspend(); // DEADLOCK-PRONE!
threadSuspended = !threadSuspended;
}
Можно избежать использования Thread.suspend и Thread.resume заменяя обработчик событий выше:
public synchronized void mousePressed(MouseEvent e) {
e.consume();
threadSuspended = !threadSuspended;
if (!threadSuspended)
notify();
}
и добавление следующего кода к "выполненному циклу":
synchronized(this) {
while (threadSuspended)
wait();
}
wait метод бросает InterruptedException, таким образом, это должно быть внутри a try ... catch пункт. Прекрасно поместить это в тот же самый пункт как sleep. Проверка должна следовать (а не предшествовать), sleep таким образом, окно было сразу перекрашено, когда поток "возобновляется". Получающееся run метод следует:
public void run() {
while (true) {
try {
Thread.sleep(interval);
synchronized(this) {
while (threadSuspended)
wait();
}
} catch (InterruptedException e){
}
repaint();
}
}
Отметьте что notify в mousePressed метод и wait в run метод внутри synchronized блоки. Это требуется языком, и гарантирует это wait и notify должным образом сериализируются. На практике это устраняет условия состязания, которые могли заставить "приостановленный" поток пропускать a notify и останьтесь временно отстраненными неопределенно. В то время как стоимость синхронизации в Java уменьшается, поскольку платформа назревает, это никогда не будет свободно. Простой прием может использоваться, чтобы удалить синхронизацию, которую мы добавили к каждой итерации "выполненного цикла." Синхронизируемый блок, который был добавлен, заменяется немного более сложной частью кода, который вводит синхронизируемый блок, только если поток был фактически приостановлен:
if (threadSuspended) {
synchronized(this) {
while (threadSuspended)
wait();
}
}
В отсутствие явной синхронизации threadSuspended должен быть сделан volatile, чтобы гарантировать быструю передачу приостанавливать-запроса.
Получающеесяrun метод:
private volatile boolean threadSuspended;
public void run() {
while (true) {
try {
Thread.sleep(interval);
if (threadSuspended) {
synchronized(this) {
while (threadSuspended)
wait();
}
}
} catch (InterruptedException e){
}
repaint();
}
}
Чтобы исправить эту ситуацию, метод stop должен гарантировать, что целевой поток сразу возобновляется, если это приостанавливается. Как только целевой поток возобновляется, он должен сразу распознать, что был остановлен, и выходит корректно. Вот то, как получающиеся методы run И stop смотрят:
public void run() {
Thread thisThread = Thread.currentThread();
while (blinker == thisThread) {
try {
Thread.sleep(interval);
synchronized(this) {
while (threadSuspended && blinker==thisThread)
wait();
}
} catch (InterruptedException e){
}
repaint();
}
}
public synchronized void stop() {
blinker = null;
notify();
}
Если вызовы метода stop Thread.interrupt, как описано выше, это не должно вызвать notify также, но это все еще должно синхронизироваться. Это гарантирует, что целевой поток не будет пропускать прерывание из-за состояния состязания. Thread.destroy?Thread.destroy никогда не реализовывался и был осужден. Если бы это было реализовано, то это было бы склонным к мертвой блокировке таким образом Thread.suspend. (Фактически, это примерно эквивалентно Thread.suspend без возможности последующего Thread.resume.) Runtime.runFinalizersOnExit осуждаемый?Далее, вызов не "ориентирован на многопотоковое исполнение" в том смысле, что он устанавливает VM-глобальный флаг. Это вынуждает каждый class с финализатором защитить против завершения живых объектов!