Alternativa ao spinlock
-
24-09-2019 - |
Pergunta
Estou usando a seguinte abordagem de spinlock:
while(!hasPerformedAction()){
//wait for the user to perform the action
//can add timer here too
}
setHasPerformedAction(false);
return getActionPerfomed();
Isso basicamente espera que um usuário execute uma ação e depois a retorne. Atualmente, algo solicita uma resposta do usuário antes de continuar, é por isso que espero até que a entrada seja recebida. No entanto, eu queria saber se isso é ineficiente e se estamos esperando por um tempo (ou seja, <= 30 segundos), isso diminuirá o PC que está executando este aplicativo. Existem outras alternativas usando essa abordagem, isto é, semáforos, se sim, qual é a sintaxe?
Obrigado,
Aly
Solução
De fato, isso não é apenas ineficiente, mas também é garantido funcionar, pois não há uma borda "antes" no código que você está mostrando. Para criar um acontece antes da borda você precisa fazer um de:
- Acesse uma variável volátil
- Sincronizar em um recurso compartilhado
- Use um bloqueio de utilitários simultâneos.
Como mencionado em outro comentário, o mais fácil A solução é simplesmente garantir que sua bandeira seja uma variável volátil e simplesmente jogue um sono curto no seu loop.
No entanto, a melhor coisa a fazer seria sincronizar/esperar/notificar em uma variável compartilhada.
Os métodos que você precisa ler são esperar e notificar. Para uma descrição melhor sobre como usá -los, leia Este artigo. Um exemplo de código de código é mostrado abaixo;
Tópico 1
Object shared = new Object();
startThread2(shared);
synchronized (shared) {
while (taskNotDone())
shared.wait();
}
Tópico 2
// shared was saved at the start of the thread
// do some stuff
markTaskAsDone();
synchronized (shared) {
shared.notify();
}
Outras dicas
O que você escreveu é chamado de loop ocupado, o que você nunca deve fazer.
Você pode continuar fazendo isso, mas pelo menos dormir um pouco para não estar ocupado em loop, o que ainda não seria tão bom:
while( !hasPerformedAction() ) {
(sleep a bit here)
}
Outra maneira de fazê -lo seria para envolver as ações do usuário em uma fila de bloqueio: então você pode simplesmente estar usando um fila.take E a implementação da fila cuidaria do problema para você.
E outra maneira seria usar um retorno de chamada para ser notificado das ações do usuário.
Os tutoriais do Java têm uma boa lição sobre a simultaneidade em Java:
http://java.sun.com/docs/books/tutorial/essential/concurrency/
Se você vai modificar a interface do usuário de outro tópico, você deve se lembrar de fazer:
SwingUtils.invokeLater(actionToInvoke);
Há um GUI Em suas tags, então assumirei que a ação é feita na GUI.
A maneira "recomendada" de fazer esse tipo de coisa é para o tópico principal se colocar para dormir (talvez usando wait()
) e para a ação da GUI para notify()
De volta à vigília, uma vez que a ação for realizada.
Existem algumas aulas para isso em java.util.concurrent.locks
. Dê uma olhada na aula LockSupport
Atenciosamente Mike