Um semáforo em Java é um auxílio de sincronização que restringe o número de threads que podem acessar um recurso compartilhado a qualquer momento. Faz parte do pacote java.util.concurrent e é usado para gerenciar o acesso simultâneo a recursos, como arquivos, bancos de dados ou conexões de rede.
Um semáforo controla o acesso a um determinado número de licenças. Cada licença representa o direito de acesso a um recurso específico. O semáforo registra o número de permissões disponíveis, o que determina quantas threads podem acessar o recurso simultaneamente.
Permit : um token ou ticket que permite que um thread prossiga com o acesso a um recurso compartilhado.
Ao criar um semáforo, você especifica o número de licenças disponíveis. Este número define quantos threads podem acessar o recurso simultaneamente.
Antes que um thread possa acessar o recurso, ele deve adquirir uma permissão do semáforo. Isso é feito usando o método acquire().
Acquire : Este método é chamado quando um thread deseja acessar o recurso. Se uma licença estiver disponível, o semáforo diminui o número de licenças disponíveis e permite que o encadeamento prossiga. Se nenhuma permissão estiver disponível, o thread será bloqueado até que uma permissão seja disponibilizada.
Comportamento de bloqueio : Se nenhuma permissão estiver disponível, o thread que chama adquirir() será bloqueado (ou seja, irá esperar) até que outro thread libere uma permissão.
Depois que um thread terminar de usar o recurso, ele deverá liberar a permissão para disponibilizá-lo para outros threads. Isso é feito usando o método release().
Release : Este método aumenta o número de licenças disponíveis. Se houver algum thread aguardando permissão, um deles será desbloqueado e poderá adquirir a licença.
Existem dois tipos de semáforos em Java:
Para entender melhor como funcionam os semáforos, vejamos uma implementação prática. Criaremos um cenário simples onde vários threads tentam acessar um recurso limitado.
import java.util.concurrent.Semaphore; public class SemaphoreDemo { // Creating a semaphore with 3 permits private static final Semaphore semaphore = new Semaphore(3); public static void main(String[] args) { // Creating and starting 6 threads for (int i = 1; i2.2 Explicação do Código
Neste exemplo, criamos um semáforo com três permissões, o que significa que apenas três threads podem acessar a seção crítica do código a qualquer momento. Em seguida, criamos seis threads, todos tentando adquirir uma licença. Depois que um thread adquire uma permissão, ele simula algum trabalho dormindo por dois segundos antes de liberar a permissão.
2.3 Observando o Resultado
Quando você executa o código acima, a saída será semelhante a esta:
Worker 1 is trying to acquire a permit... Worker 1 acquired a permit. Worker 2 is trying to acquire a permit... Worker 2 acquired a permit. Worker 3 is trying to acquire a permit... Worker 3 acquired a permit. Worker 4 is trying to acquire a permit... Worker 5 is trying to acquire a permit... Worker 6 is trying to acquire a permit... Worker 1 is releasing a permit. Worker 4 acquired a permit. Worker 2 is releasing a permit. Worker 5 acquired a permit. Worker 3 is releasing a permit. Worker 6 acquired a permit.Aqui, os três primeiros threads adquirem as permissões com sucesso e iniciam suas tarefas. Os threads restantes devem esperar até que uma licença seja liberada antes de poderem prosseguir.
2.4 Casos de uso prático
Os semáforos são particularmente úteis em cenários onde você precisa limitar o número de acessos simultâneos a um recurso específico, como:
Embora os semáforos sejam uma ferramenta poderosa, eles vêm com seu próprio conjunto de vantagens e desvantagens.
Flexibilidade : Os semáforos permitem controle preciso sobre o acesso a recursos por vários threads.
Escalabilidade : Os semáforos podem gerenciar facilmente o acesso a um grande número de recursos.
Fairness : Os semáforos podem ser configurados para garantir que os threads adquiram licenças de maneira justa.
Complexidade : o uso de semáforos pode introduzir complexidade em seu código, dificultando a depuração.
Deadlocks : Se não forem tratados corretamente, os semáforos podem levar a deadlocks onde os threads são bloqueados indefinidamente aguardando permissões.
Para evitar armadilhas comuns e aproveitar ao máximo os semáforos, considere as seguintes práticas recomendadas:
Em vez de usar adquirir(), que bloqueia indefinidamente, você pode usar tryAcquire() para tentar adquirir uma licença com tempo limite. Isso evita que os threads fiquem presos esperando.
if(semaphore.tryAcquire(1000, TimeUnit.MILLISECONDS)) { try { // Critical section } finally { semaphore.release(); } }
Para evitar vazamentos de recursos, sempre libere a licença em um bloco finalmente. Isso garante que a licença seja liberada mesmo que ocorra uma exceção.
Se você precisar apenas bloquear e desbloquear um recurso para um único thread, considere usar ReentrantLock ou sincronizado em vez de um semáforo binário.
Semáforos são uma ferramenta poderosa para gerenciar simultaneidade em Java, permitindo controlar o número de threads que acessam um recurso compartilhado. Seguindo as técnicas e práticas recomendadas descritas neste artigo, você pode implementar semáforos com eficácia em seus aplicativos Java para garantir um gerenciamento de recursos seguro e eficiente.
Se você tiver alguma dúvida ou quiser compartilhar suas próprias experiências com semáforos, fique à vontade para comentar abaixo!
Leia mais postagens em: Técnicas para gerenciar simultaneidade em Java usando semáforos
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3