Uma grande dúvida, exige um resposta grande...
B) Outra thread na qual percente o bloqueio do objeto invoca o método notify all;
Quando você chama o wait(), abre mão do objeto (chamador de monitor), e outras threads poderão entrar no código sincronizado.
Se uma thread percorrer um outro bloco, que contém como chave de sincronização o mesmo monitor, e chamar notify() ou notifyAll(), sua thread poderá sair do wait, e reobter o monitor para prosseguir a execução no bloco sincronizado.
Esse comportamento é descrito no próprio javadoc do método wait:
"This method causes the current thread (call it T) to place itself in the wait set for this object and then to relinquish any and all synchronization claims on this object. (...)"
Lembre-se a assinatura do synchronized é:
synchronized (<objeto monitor>) {
//Código sincronizado
}
Por exemplo na classe abaixo:
public class Sleeper() {
boolean isSleeping = false;
public void delay(int millis) {
if (millis <= 0) return;
synchronized (this) { //This é o monitor
isSleeping = true;
try {
while (isSleeping)
wait(millis);
} catch (InterruptedException e) {}
}
}
public void wakeUp() {
synchronized (this) {
isSleeping = false;
notifyAll();
}
}
}
Uma thread (A) poderia chamar o método sleep e seria posta para dormir. Isso liberaria o monitor this. Outra thread (B), então, chama o método wakeUp(). B consegue entrar no corpo do bloco sincronizado, pois o this não pertence mais a thread A. B troca o valor de isSleeping e então chama notifyAll e, assim que sair do bloco sincronizado, a thread A irá acordar e continuar sua execução. Veja ainda este exemplo com um programa com esse mecanismo funcionando.
E) Outra Thread invoca o interrupt() na Thread
Quando outra thread invoca o método interrupt, todos os waits são abandonados e lançam uma interrupted exception. Embora o interrupt possa ser usado como um mecanismo de parada para a thread, isso não é muito recomendado. Considere o uso de interrupt para o uso da VM, quando a aplicação estiver sendo finalizada. Veja este exemplo, onde um grupo de threads é parado chamando interrupt.
Note que, se você tivesse colocado o try..catch do InterruptedException dentro do while, a thread não seria interrompida. Via de regra, não faça isso. Considere que o interrupt é lançado ao final da sua aplicação, saia do while e rode algum código de finalização (fechamento de arquivo, sockets ou outros recursos que seu objeto possam estar em uso).
Existem ainda uma outras situações, que não foram descritas por essa questão, e geralmente geram dúvida:
G) O wait termina antes do prazo, sem motivo aparente algum.
É verdade. Esse comportamento é chamado de spurious wakeup e você pode até mesmo encontrar a descrição dele no javadoc do método wait(). Isso normalmente não é problema, pois o wait é precedido de uma condição, que o mantém num while (como na classe acima, a condição é isSleeping). Mas pode dar um pouco de trabalho caso o seu sistema exija que o timeout do wait seja rigorosamente cumprido.
H) Outra thread invoca o stop() na thread
Em primeiríssimo lugar, é importante lembrar que o stop é um método deprecated. Quando você pega o objeto que descreve a thread e chama stop nele, a thread é imediatamente interrompida. Não interessa se ela está ou não bloqueada. Nenhum código de finalização é chamado. Via de regra, não use esse recurso. Pode clicar aqui para uma descrição mais detalhada do porquê.