Pergunta

Alguém no trabalho apenas nos pediu para o raciocínio por trás ter que quebrar uma espera dentro de um sincronizado.

Honestamente, eu não posso ver o raciocínio. Eu entendo o que os javadocs dizem - que as necessidades de rosca ser o proprietário do monitor do objeto, mas por quê? Que problemas não impede? (E se é realmente necessário, por que não pode o método espera obter do próprio monitor?)

Eu estou procurando um motivo ou talvez uma referência bastante em profundidade para um artigo. Eu não poderia encontrar uma em um google rápido.

Oh, também, como é que Thread.sleep comparar?

edit:. Grande conjunto de respostas - Eu realmente gostaria de poder selecionar mais de um, porque todos eles me ajudou a entender o que estava acontecendo

Foi útil?

Solução

Se o objeto não possui o monitor objeto quando ele chama Object.wait (), ele não será capaz de acessar o objeto para configurar um ouvinte notificar até que o monitor é liberado. Em vez disso, ele será tratado como um fio tentando acessar um método em um objeto sincronizado.

Ou, dito de outra forma, não há diferença entre:

public void doStuffOnThisObject()

e o método seguinte:

public void wait()

Ambos os métodos serão bloqueados até que o monitor objeto é liberado. Esta é uma característica em Java para evitar que o estado de um objeto que está sendo atualizado por mais de um segmento. Ele simplesmente tem consequências não intencionais no método wait ().

Provavelmente, o método wait () não está sincronizado, porque isso poderia criar situações em que o segmento tem vários bloqueios no objeto. (Veja Linguagem Java Especificações / Bloqueio para mais informações sobre este assunto.) vários bloqueios são um problema porque o método wait () só irá desfazer um bloqueio. Se o método foram sincronizados, seria garantir que somente o método de bloqueio seria desfeita ao mesmo tempo deixando um potencial desfeita bloqueio exterior. Isso criaria uma condição de impasse no código.

Para responder à sua pergunta sobre Thread.sleep (), Thread.sleep () não garante que qualquer condição que você está esperando foi cumprida. Usando Object.wait () e Object.notify () permite a um programador para implementar manualmente bloqueio. Os tópicos vão desbloquear uma vez por notificar é enviado que uma condição foi cumprida. por exemplo. A leitura do disco ter terminado e os dados podem ser processados ??pelo fio. Thread.sleep () exigiria que o programador sondagem se a condição foi cumprida, em seguida, voltar a dormir se não tem.

Outras dicas

Muitas boas respostas aqui já. Mas só quero mencionar aqui que o outro deve fazer ao usar wait () é fazê-lo em um loop depende da condição que você está esperando, caso você esteja vendo wakeups espúrias, que na minha experiência fazer acontecer.

Para esperar por algum outro segmento para alterar a condição de verdadeiro e notificadas:

synchronized(o) {
  while(! checkCondition()) {
    o.wait();
  }
}

É claro que, nestes dias, eu recomendo apenas usando o novo objeto circunstância que é mais claro e tem mais recursos (como permitir que várias condições por bloqueio, ser capaz de verificar o comprimento da fila de espera, mais flexível cronograma / interrupção, etc ).

 Lock lock = new ReentrantLock();
 Condition condition = lock.newCondition();
 lock.lock();
 try {
   while (! checkCondition()) {
     condition.await();
   }
 } finally {
   lock.unlock();
 }

}

É necessário possuir o monitor, uma vez que o objetivo do wait () é liberar o monitor e deixar outros tópicos obter o monitor para fazer o processamento da sua própria. A finalidade destes métodos (espera / notificar) é coordenar o acesso a blocos de código sincronizado entre dois segmentos que requerem uns aos outros para executar algumas funcionalidades. Não é simplesmente uma questão de ter certeza que o acesso a uma estrutura de dados é threadsafe, mas para coordenar eventos entre vários segmentos.

Um exemplo clássico seria um caso de produtor / consumidor onde um fio envia dados para uma fila, e outro segmento consome os dados. O fio consumindo sempre requer o monitor para acessar a fila, mas iria liberar o monitor uma vez que a fila está vazia. O segmento produtor, então, só tem acesso a escrita para o segmento quando o consumidor não é mais processamento. Seria notificar o segmento do consumidor, uma vez que tem empurrado mais dados para a fila, para que ele possa recuperar o monitor e acesso a fila novamente.

Aguarde dá-se o monitor, então você deve tê-lo a desistir. Notificar deve ter o monitor também.

A principal razão por que você quer fazer isso é garantir que você tem o monitor quando você voltar de espera () - normalmente, você está usando a espera / notificar protocolo para proteger algum recurso compartilhado e você quer que ele ser seguro para tocá-lo quando esperar retornos. O mesmo com notificar - geralmente você está mudando alguma coisa e, em seguida, chamando notificar () -. Você quer ter o monitor, fazer alterações e chamada notificar ()

Se você fez uma função como esta:

public void synchWait() {
   syncronized { wait(); }
}

Você não teria o monitor quando espera voltou -. Você poderia obtê-lo, mas você não pode obtê-lo no próximo

Aqui está o meu entendimento sobre por que a restrição é realmente uma exigência. Eu estou baseando esta sobre a implementação monitor de um C ++ eu fiz um tempo atrás, combinando um mutex e uma variável de condição.

Em um mutex + condition_variable = Monitor sistema, o esperar chamada define a variável de condição em um estado de espera e libera o mutex. A variável de condição é o estado compartilhado, por isso precisa ser bloqueado para evitar condições de corrida entre threads que querem esperar e tópicos que deseja notificar. Em vez de introduzir mais uma extensão mútua para bloquear o seu estado, a exclusão mútua existente é utilizado. Em Java, o mutex está correctamente bloqueada quando o fio-de esperar cerca de-proprietária do monitor.

Na maior parte de espera é feito se houver uma condição de dizer uma fila está vazia.

If(queue is empty)
     queue.wait();

Vamos assumir a fila está vazia. No caso, se o atual segmento-empts pré após a verificação da fila, em seguida, se outro fio acrescenta alguns elementos à fila, o thread atual não vai saber e vai para a espera Estado. Isto é errado. Assim, devemos ter algo parecido

Synchornized(queue)
{
   if(queue is empty)
          queue.wait();
}

Agora, vamos considerar o que se eles fizeram esperar-se como sincronizado. Como já foi mencionado em um dos comentários, ele libera apenas um bloqueio. Isso significa que se espera () foi sincronizada no código acima apenas um bloqueio teria sido liberada. Implica que thread atual vai para esperar com a trava para a fila.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top