[RESOLVIDO]Thread notify()

Estou meio confuso na seguinte questão

A resposta correta é a E , mas o notify nao escolhe aleatoriamente , ou esta sendo um erro de interpretação meu?

Obrigado desde ja

Como quem faz a escolha de quem vai acordar é o sistema operacional, quando ocorre um notify() não é possível saber qual das threads esperando o wait() será acordada. Por isso, recomenda-se usar o notifyAll(). Ele garante que todas as threads serão notificadas, assim seu sistema não travará caso a primeira thread acordada não possa processar por algum motivo.

Brow da uma lida em

http://www.coderanch.com/t/418141/java-programmer-SCJP/certification/notify,
Tem uma discução sobre isso ai que vc ta perguntando pelo que eu vi é isso ai mesmo
que o vinny falou. Mas da uma olhada…

Proteja seu lock e sempre use notify() ao invés de notifyAll().

notifyAll só deve ser usado se seu problema pede isso.

Senão, como disse o Saoj, deve-se usar notify (e talvez você precise de usar um try/finally para forçar a dar o tal do notify se a thread que deveria dar o notify não conseguir dá-lo adequadamente).

O que às vezes (principalmente em Unix/Linux/MacOSX pode ocorrer) é uma outra coisa, que é o “wait” acordar sem ser por causa de um “notify”.

[quote=entanglement]notifyAll só deve ser usado se seu problema pede isso.

Senão, como disse o Saoj, deve-se usar notify (e talvez você precise de usar um try/finally para forçar a dar o tal do notify se a thread que deveria dar o notify não conseguir dá-lo adequadamente).

O que às vezes (principalmente em Unix/Linux/MacOSX pode ocorrer) é uma outra coisa, que é o “wait” acordar sem ser por causa de um “notify”.

[quote]
A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops, like this one:

     synchronized (obj) {
         while (<condition does not hold>)
             obj.wait(timeout);
         ... // Perform action appropriate to condition
     }

[/quote][/quote]

Verdade, também conhecido como spurious wakeup. Um while ao invés de if resolve.

Protegendo o lock:

Bad:

public synchronized void add(..) {

}

Good:

public void add(...) {
   synchronized(lock) {

   }
}

Estranho, a recomendação que sempre leio é a inversa.
Geralmente você irá usar notifyAll().

O notify() é apenas se você pode garantir uma dessas condições:

  • Todas as threads seguem condições identicas;
  • Todas as threads fazem o mesmo conjunto de operações após acordar. Isto é, qualquer thread que acordar irá finalizar sua operação após o notify();
  • Você tem apenas uma única thread aguardando notificação.

Aqui tem algumas referências que explicam melhor o porque.
https://www.securecoding.cert.org/confluence/display/java/THI02-J.+Notify+all+waiting+threads+rather+than++a+single+thread

Mas a dica de preferir notifyAll no lugar de notify() eu vi no livro do Goetz.

[quote=ViniGodoy]Estranho, a recomendação que sempre leio é a inversa.
Geralmente você irá usar notifyAll().

O notify() é apenas se você pode garantir uma dessas condições:

  • Todas as threads seguem condições identicas;
  • Todas as threads fazem o mesmo conjunto de operações após acordar. Isto é, qualquer thread que acordar irá finalizar sua operação após o notify();
  • Você tem apenas uma única thread aguardando notificação.

Aqui tem algumas referências que explicam melhor o porque.
https://www.securecoding.cert.org/confluence/display/java/THI02-J.+Notify+all+waiting+threads+rather+than++a+single+thread
http://stackoverflow.com/a/3186336

Mas a dica de preferir notifyAll no lugar de notify() eu vi no livro do Goetz.[/quote]

notifyAll() livra o programador de alguma cagada que ele fez, mas é MENOS performático que notify() por razões óbvias.

Se vc tem um lock, o que adianta acordar todos os threads esperando nesse lock se apenas um vai conseguir adquiri-lo?

Geralmente (mas nem sempre) quando estamos esperando num lock, queremos adiquiri-lo ao acordar.

A condicao problemática, por exemplo, é um blocking queue que não protegeu o seu lock. Então se algum maluco dá um wait no seu lock não-protegido e vc usa notify() ao invés de notifyAll() vc quebrou o seu queue.

Se o seu sistema não é de performance crítica então sempre use notifyAll e seja feliz.

Desculpe a demora para responder, estava com alguns probleminhas aqui :oops: .

Referente a implementação de qual seria melhor eu entendi conforme explicado aqui por todos, mas na resposta da questão me parece da maneira que foi redigido , que , ao executar o método notify() existe uma “regra” para escolher qual sera notificada.

Eu estou interpretando a resposta erroneamente, ou a questão nao foi bem redigida, pois para mim a thread notifica aleatoriamente as threads que estão esperando.

Muito obrigado até agora a todos!

Arbitrality significa que o notify escolhe de maneira arbitrária, segundo critérios dele, que não estão sob o controle do programador.
Isso pq é o que o SO faz. Para nós, é como se fosse aleatório, já que não temos qualquer controle ou forma de prever quem será escolhido.

[quote=ViniGodoy]Arbitrality significa que o notify escolhe de maneira arbitrária, segundo critérios dele, que não estão sob o controle do programador.
Isso pq é o que o SO faz. Para nós, é como se fosse aleatório, já que não temos qualquer controle ou forma de prever quem será escolhido.[/quote]

E isso pode causar thread starvation se vc tiver um caminhã de threads, ou seja, um deles por azar nunca vai pegar o lock e esperar para sempre. Se isso for um problema vc pode usar ReentrantLock que te dá a opcão (um pouco mais custosa) de fairness, ou seja, uma FIFO queue para as threads pegarem o lock em ordem.

Claro que notifyAll() tb não resolve starvation.

[quote=saoj]E isso pode causar thread starvation se vc tiver um caminhã de threads, ou seja, um deles por azar nunca vai pegar o lock e esperar para sempre. Se isso for um problema vc pode usar ReentrantLock que te dá a opcão (um pouco mais custosa) de fairness, ou seja, uma FIFO queue para as threads pegarem o lock em ordem.

Claro que notifyAll() tb não resolve starvation.[/quote]

Embora todos os SOs que a VM padrão Oracle suporta não gerem starvation.
Só é importante estar atento caso você queira sua aplicação em dispositivos mais “exóticos”.

[quote=ViniGodoy][quote=saoj]E isso pode causar thread starvation se vc tiver um caminhã de threads, ou seja, um deles por azar nunca vai pegar o lock e esperar para sempre. Se isso for um problema vc pode usar ReentrantLock que te dá a opcão (um pouco mais custosa) de fairness, ou seja, uma FIFO queue para as threads pegarem o lock em ordem.

Claro que notifyAll() tb não resolve starvation.[/quote]

Embora todos os SOs que a VM padrão Oracle suporta não gerem starvation.
Só é importante estar atento caso você queira sua aplicação em dispositivos mais “exóticos”.[/quote]

Não sabia. Vc diz então que notify() não é verdadeiramente aleatório? Fairness tem um custo, logo acredito que por padrão o SO não deveria utilizá-lo. Vc ativa se precisar.

Notify pode ser utilizado em vez de notifyAll apenas quando as duas condições seguintes forem verdadeiras:

Uniform waiters. Apenas uma condição está associada ao conjunto de threads e cada segmento executa a mesma lógica ao retornar da espera.
One-in, one-out. A notificação sobre a variável de condição permite no máximo uma thread prosseguir.

Não verdadeiramente aleatório, isso depende do scheduler do SO. Thread priorities também podem modificar como o scheduler trabalha, no java todas threads por default são Thread. NORM. É possível modificar esse
comportamento, mas na realidade é só uma dica não necessariamente se comportará igual em todos os SOs e isso claramente pode levar a Starvation caso mal projetado.

[quote=Laubstein, M?cio]Não verdadeiramente aleatório, isso depende do scheduler do SO. Thread priorities também podem modificar como o scheduler trabalha, no java todas threads por default são Thread. NORM. É possível modificar esse
comportamento, mas na realidade é só uma dica não necessariamente se comportará igual em todos os SOs e isso claramente pode levar a Starvation caso mal projetado.[/quote]

Assumindo a mesma prioridade, eu acharia que é aleatório, tanto é que o ReentrantLock te dá a opcão de fairness que não é aleatorio (FIFO) mas tem seu custo.

Eles usam algorítmos de escalonamento que garantem a ausência de starvation, um dos exemplos mais antigos é o Round Robin. Ainda no Windows XP, ele já era usado com prioridades e um conceito chamado de aging. A idéia do envelhecimento é aumentar em 1 a prioridade de um processo sempre que ele não é executado, e isso elimina o starvation (ainda que um processo tenha prioridade 1, ele cedo ou tarde será mais prioritário que um processo de prioridade 100).

Hoje usam-se algorítmos que sejam mais adequados a multiplos núcleos.

Mas claro, vc não pode contar com o SO se sua aplicação for ser muito multiplataforma. Se estiver fazendo uma lib, por exemplo, você nunca pode esperar onde o cara que fez sua lib vai usa-la. Nesse caso, é melhor garantir um escalonamento justo via software.

Nesse material há uma boa explicação sobre diversos algorítmos: http://dainf.ct.utfpr.edu.br/~maziero/lib/exe/fetch.php/so:so-cap02.pdf

Agora entendi , no meu caso foi um erro de interpretação, mas estou vendo que esse tópico foi muito além do que eu tinha perguntado, o que é uma coisa ótima, pois acabei me aprofundando mais no assunto e compreedendo melhor os conceitos apresentados.

Muito obrigado a todos :wink:!