Estou criando um aplicativo Java com um thread de lógica de aplicativo e um thread de acesso ao banco de dados. Ambos persistem por toda a vida útil do aplicativo e precisam estar em execução ao mesmo tempo (um fala com o servidor, outro com o usuário; quando o aplicativo é totalmente iniciado, preciso que ambos trabalhem).
No entanto, na inicialização, preciso garantir que, inicialmente, o encadeamento do aplicativo aguarde até que o encadeamento db esteja pronto (atualmente determinado pela pesquisa de um método personalizado dbthread.isReady()
). Eu não me importaria se o segmento de aplicativo bloqueie até que o segmento db esteja pronto.
Thread.join()
não parece uma solução - o encadeamento db só sai no encerramento do aplicativo.
while (!dbthread.isReady()) {}
funciona, mas o loop vazio consome muitos ciclos do processador.
Alguma outra ideia? Obrigado.
fonte
a
estiver aguardando um objeto,synchronised(object)
como outro thread pode passarsynchronized(object)
para chamarobject.notifyAll()
? No meu programa, tudo ficou preso emsynchronozed
blocos.object.wait()
efetivamente desbloqueando a trava naquele objeto. Quando o segundo thread "sai" de seu bloco sincronizado, os outros objetos são liberados dowait
método e obtêm novamente o bloqueio naquele momento.Use um CountDownLatch com um contador de 1.
Agora, no tópico do aplicativo,
No encadeamento db, depois de concluir, faça -
fonte
countDown()
umfinally{}
blocoRequerimento ::
Responda ::
Tarefa concluída!! Veja o exemplo abaixo
Saída deste programa:
Você pode ver que demora 6 segundos antes de concluir sua tarefa, que é maior que o outro encadeamento. Então Future.get () aguarda até que a tarefa seja concluída.
Se você não usar future.get (), ele não espera para terminar e executa o consumo de tempo baseado.
Boa sorte com a concorrência Java.
fonte
CountdownLatch
es, mas a sua é uma abordagem muito mais flexível.Muitas respostas corretas, mas sem um exemplo simples. Aqui está uma maneira fácil e simples de como usar
CountDownLatch
:fonte
Use esta classe assim:
Crie um ThreadEvent:
No método, isso está aguardando resultados:
E no método que está criando os resultados após a criação de todos os resultados:
EDITAR:
(Desculpe por editar esta postagem, mas esse código tem uma condição de corrida muito ruim e eu não tenho reputação suficiente para comentar)
Você só pode usar isso se tiver 100% de certeza de que o sinal () é chamado após aguardar (). Esse é o grande motivo pelo qual você não pode usar objetos Java como, por exemplo, Windows Events.
O se o código for executado nesta ordem:
então o thread 2 esperará para sempre . Isso ocorre porque Object.notify () ativa apenas um dos threads em execução no momento. Um encadeamento aguardando mais tarde não é ativado. Isso é muito diferente de como eu espero que os eventos funcionem, onde um evento é sinalizado até que a) espere ou b) reinicie explicitamente.
Nota: Na maioria das vezes, você deve usar notifyAll (), mas isso não é relevante para o problema "espere para sempre" acima.
fonte
Experimente a classe CountDownLatch fora do
java.util.concurrent
pacote, que fornece mecanismos de sincronização de nível superior, que são muito menos propensos a erros do que qualquer material de baixo nível.fonte
Você pode fazer isso usando um objeto Exchanger compartilhado entre os dois threads:
E no segundo segmento:
Como já foi dito, não use esse código alegre e apenas copie e cole. Faça algumas leituras primeiro.
fonte
A interface Futuro do
java.lang.concurrent
pacote foi projetada para fornecer acesso aos resultados calculados em outro encadeamento.Dê uma olhada no FutureTask e no ExecutorService para obter uma maneira pronta de fazer esse tipo de coisa.
Eu recomendo fortemente a leitura de Java Concurrency In Practice para qualquer pessoa interessada em simultaneidade e multithreading. Obviamente, ele se concentra em Java, mas há muita carne para quem trabalha em outras linguagens também.
fonte
Se você quiser algo rápido e sujo, basta adicionar uma chamada Thread.sleep () dentro do seu loop while. Se a biblioteca do banco de dados é algo que você não pode mudar, não há outra solução fácil. A pesquisa no banco de dados até que esteja pronto com um período de espera não prejudica o desempenho.
Dificilmente algo que você poderia chamar de código elegante, mas realiza o trabalho.
Caso você possa modificar o código do banco de dados, é melhor usar um mutex como proposto em outras respostas.
fonte
Isso se aplica a todos os idiomas:
Você deseja ter um modelo de evento / ouvinte. Você cria um ouvinte para aguardar um evento específico. O evento seria criado (ou sinalizado) no seu thread de trabalho. Isso bloqueará o encadeamento até que o sinal seja recebido em vez de pesquisar constantemente para verificar se uma condição é atendida, como a solução que você possui atualmente.
Sua situação é uma das causas mais comuns de conflitos - certifique-se de sinalizar o outro encadeamento, independentemente dos erros que possam ter ocorrido. Exemplo - se seu aplicativo lança uma exceção - e nunca chama o método para sinalizar ao outro que as coisas foram concluídas. Isso fará com que o outro thread nunca 'acorde'.
Sugiro que você analise os conceitos de uso de eventos e manipuladores de eventos para entender melhor esse paradigma antes de implementar seu caso.
Como alternativa, você pode usar uma chamada de função de bloqueio usando um mutex, o que fará com que o encadeamento aguarde a liberação do recurso. Para fazer isso, você precisa de uma boa sincronização de threads, como:
fonte
Você pode ler de uma fila de bloqueio em um thread e gravá-lo em outro thread.
fonte
Desde a
join()
foi descartadoVocê pode considerar outras alternativas:
invokeAll from
ExecutorService
ForkJoinPool ou newWorkStealingPool de
Executors
(desde o lançamento do Java 8)fonte
Esta ideia pode ser aplicada? Se você usa CountdownLatches ou Semaphores funciona perfeitamente, mas se você está procurando a resposta mais fácil para uma entrevista, acho que isso pode ser aplicado.
fonte