Bloqueando filas em java
1. O que é uma fila de bloqueio?
Uma fila de bloqueio (BlockingQueue) é uma fila que suporta duas operações adicionais. Essas duas operações adicionais são:
Quando a fila estiver vazia, o fio que busca o elemento aguarda a fila se tornar não vazio.
Quando a fila estiver cheia, o thread que armazena os elementos aguardam a fila estar disponível.
As filas de bloqueio são frequentemente usadas em cenários de produtores e consumidores. Os produtores são threads que adicionam elementos às filas, e os consumidores são threads que retiram elementos das filas. Uma fila de bloqueio é o contêiner onde o produtor armazena elementos, e o consumidor leva apenas elementos do contêiner.
2. Fila de bloqueio em java
Sete filas de bloqueio são fornecidas no JDK:
ArrayblockingQueue
ArrayblockingQueue é uma fila de bloqueio limitada implementada usando matrizes. Esta fila classifica os elementos de acordo com o primeiro princípio da primeira saída (FIFO). Por padrão, os visitantes não têm certeza de acessar de maneira justa. A chamada fila razoavelmente acessível refere-se a todos os threads de produtores bloqueados ou threads de consumo. Quando a fila está disponível, a fila pode ser acessada na ordem de bloqueio. Ou seja, o thread do produtor que bloqueia primeiro pode inserir elementos na fila primeiro, e o thread do consumidor que bloqueia primeiro pode obter elementos da fila primeiro. Normalmente, a taxa de transferência é reduzida para garantir a justiça . Podemos criar uma fila de bloqueio justo usando o seguinte código:
ArrayblockingQueue Fairqueue = novo ArrayBlockingQueue (1000, True);
A justiça de seu acesso é alcançada através da trava do Reentrantlock.
LinkedBlockingQueue
O LinkedBlockingQueue é uma fila de bloqueio limitada implementada com listas vinculadas. O comprimento padrão e o máximo desta fila é inteiro.max_value. Esta fila classifica os elementos de acordo com o primeiro princípio da primeira saída.
PriorityBlockingQueue
O PriorityBlockingQueue é uma fila ilimitada que suporta prioridade. Por padrão, os elementos são organizados em ordem natural e as regras de ordem dos elementos também podem ser especificadas através do comparador do comparador. Os elementos são organizados em ordem crescente.
Atraso
O ALOWQUEUE é uma fila de bloqueio ilimitado que suporta a aquisição tardia de elementos. A fila é implementada usando PriorityQueue. Os elementos na fila devem implementar a interface atrasada e, ao criar um elemento, você pode especificar quanto tempo leva para obter o elemento atual da fila. Os elementos só podem ser extraídos da fila quando o atraso expirar. Podemos usar o Atraso nos cenários de aplicação a seguir:
Projeto do sistema de cache: o atraso pode ser usado para salvar o período de validade dos elementos de cache, e um encadeamento pode ser usado para consultar o atraso. Uma vez que o elemento puder ser obtido a partir do atraso, isso significa que o período de validade do cache chegou.
Cronograma de tarefas programado. Use o ALOWQUEUE para salvar as tarefas e o tempo de execução que serão executados no dia. Uma vez que a tarefa for obtida a partir do atraso, ela começará a executar. Por exemplo, o timerQueue é implementado usando o DeoundQueue.
Como implementar a interface atrasada
Podemos nos referir à aula de ScheduledFutureTask no ScheduledThreadpoolExecutor. Esta classe implementa a interface atrasada. Primeiro: ao criar um objeto, use o tempo para gravar quando o objeto puder ser usado antes da gravação. O código é o seguinte:
ScheduledFutureTask (Runnable R, V Resultado, ns longo, longo período) {super (r, resultado); this.Time = ns; this.period = período; this.sequencenumber = sequencer.getAndIncrement ();}Em seguida, use o getDelay para consultar quanto tempo o elemento atual precisa ser adiado. O código é o seguinte:
public Long GetDelay (Unidade TimeUnit) {return Unit.Convert (Time - Now (), TimeUnit.NanosEconds); }Através do construtor, podemos ver que a unidade dos parâmetros de tempo de atraso ns é nanossegundos. É melhor usar nanossegundos ao projetar você mesmo, porque você pode especificar qualquer unidade ao receber um rego. Uma vez que os nanossegundos são usados como unidade e o tempo de atraso é menor que os nanossegundos, será problemático. Ao usar, observe que, quando a hora for menor que a hora atual, o GetDelay retornará um número negativo.
Por fim, podemos usar o tempo para especificar o pedido na fila, por exemplo: seja o tempo de atraso mais longo, será colocado no final da fila.
public int compareto (atrasado outro) {if (other == this) retorna 0; if (outra instância de agendamento scheduledfutureTask) {agendadofutureTask x = (agendadofutureTask) outros; Diff longo = tempo - X.Time; if (diff <0) retornar -1; else if (diff> 0) retornar 1; caso contrário, se (sequencenumber <x.sequencenumber) retorna -1; caso contrário, retorne 1; } long d = (getDelay (timeUnit.nanosEconds) -Other.getDelay (timeUnit.nanosEconds)); retornar (d == 0)? 0: ((d <0)? -1: 1); }Como implementar filas de bloqueio atrasadas
A implementação das filas de bloqueio de atraso é muito simples. Quando o consumidor obtém elementos da fila, se o elemento não atingir o tempo de atraso, ele bloqueia o encadeamento atual.
Longo atraso = primeiro.getDelay (timeutil.nanosegunds); if (atraso <= 0) {return q.poll; // bloqueando a fila} else if (líder! = null) {// lead representa um tópico aguardando uma mensagem da fila de bloqueio disponível.await (); // Deixe o thread entrar no sinal de espera} else {// Quando o líder for nulo, defina o fio atual para liderar thisthread = thread.currentThread (); tente {líder = thisthread; // use o método AwaitNanos () para fazer o fio atual (finalmente); }}}Síncrono
O síncrono é uma fila de bloqueio que não armazena elementos. Cada operação de put deve aguardar uma operação de tomada, caso contrário, os elementos não podem ser adicionados. O síncrono pode ser considerado um passador, responsável por transmitir dados processados pelo thread do produtor diretamente para o thread do consumidor. A fila em si não armazena nenhum elemento, o que é muito adequado para cenários transitivos. Por exemplo, os dados usados em um thread são passados para outro thread para uso. A taxa de transferência do síncrono é maior que a de
LinkedBlockingQueue e ArrayBlockingQueue.
Ele suporta filas de acesso justo. Por padrão, ainda é um mecanismo de política injusto
LinkedTransferqueue
O LinkedTransferqueue é uma fila de transferência de bloqueio ilimitada composta pela estrutura da lista vinculada. Comparado com outras filas de bloqueio, o LinkedTransferqueue possui mais métodos de trytransfer e transferência.
Método de transferência
Se um consumidor estiver aguardando atualmente para receber um elemento (quando o consumidor usa o método Take () ou o método Poll () limitado pelo tempo), o método de transferência pode transferir imediatamente os elementos passados pelo produtor para o consumidor. Se nenhum consumidor estiver aguardando o elemento de recebimento, o método de transferência armazena o elemento no nó da cauda da fila e aguarda até que o elemento seja consumido pelo consumidor antes de retornar.
Método TryTransfer
É usado para testar se os elementos introduzidos pelo produtor podem ser transmitidos diretamente ao consumidor. Se nenhum consumidor estiver aguardando o elemento de recebimento, False será devolvido. A diferença entre o método de transferência é que o método TryTransfer retorna imediatamente, independentemente de o consumidor receber ou não. O método de transferência deve esperar até que o consumidor o consuma antes de retornar.
Para o método TryTransfer (e e, tempo limite de longa data, unidade de unidade de tempo) com limite de tempo, ele tenta passar o elemento aprovado pelo produtor diretamente ao consumidor, mas se não houver consumidor consumindo o elemento, ele aguardará o tempo especificado antes de retornar. Se o tempo limite não tiver consumido o elemento, ele retornará falso e se o elemento for consumido dentro do tempo limite, ele retornará verdadeiro.
LinkedBlockingDeque
O LinkedBlockingDeque é uma fila de bloqueio bidirecional composta pela estrutura da lista vinculada. A chamada fila de mão dupla refere-se ao fato de que você pode inserir e remover elementos das duas extremidades da fila. Como a fila de ponta dupla possui uma entrada adicional na fila de operação, a competição é reduzida pela metade quando vários threads se juntam à fila ao mesmo tempo. Comparado com outras filas de bloqueio, o LinkedBlockingDeque possui mais AddFirst, Addlast, Offerfirst, Offerlast, Peekfirst, Peeklast e outros métodos. O método termina com a primeira palavra, indica inserção, aquisição ou remoção do primeiro elemento da fila de ponta dupla. Um método que termina com a última palavra, indicando que o último elemento da fila de ponta dupla é inserido, obtido ou removido. Além disso, o método de inserção Add é equivalente ao Addlast, e o método de remoção remove é equivalente ao Remoffirst. No entanto, o método de Take é equivalente a Takefirst. Não sei se é um bug no JDK e é mais claro usar o método com os primeiros e os últimos sufixos ao usá -lo. A capacidade da fila pode ser inicializada ao inicializar o LinkedBlockingDeque para impedir que ele incha quando for reinsciado. Além disso, a fila de bloqueio bidirecional pode ser usada no modo "roubo de trabalho".
Obrigado pela leitura, espero que isso possa ajudá -lo. Obrigado pelo seu apoio a este site!