1. Longadder
É usado de maneira semelhante ao atômico, mas tem melhor desempenho que atômico.
Longadder e Atomiclong usam operações atômicas para melhorar o desempenho. No entanto, Longadder realiza separação de pontos quentes com base em atômico. A separação de ponto quente é semelhante a reduzir o tamanho da partícula de trava na operação bloqueada, separando uma trava em vários bloqueios para melhorar o desempenho. No bloqueio, métodos semelhantes podem ser usados para aumentar a taxa de sucesso do CAS, melhorando o desempenho.
Esquema Longadder:
O método de implementação do atômico é que existe uma variável de valor dentro. Quando vários threads são auto-incrustantes e autodenominos, todos são operados a partir do nível de instrução da máquina através das instruções do CAS para garantir a atomicidade da simultaneidade. A única razão pela qual restringe a eficiência de Atomiclong é a alta simultaneidade. A alta concorrência significa que o CAS tem uma chance maior de falha, mais tempos de nova tentativa e quanto mais threads tentam, maior a chance de falha do CAS, que se torna um ciclo vicioso, e a eficiência do atômico é reduzida.
Longadder dividirá um valor em várias células e adicionará todas as células ao valor. Portanto, ao adicionar e subtrair Longadder, você só precisa operar em diferentes células. Diferentes encadeamentos executam operações de CAS em diferentes células. Obviamente, a taxa de sucesso do CAS é alta (imagine 3+2+1 = 6, um thread 3+1, o outro thread 2+1 e, finalmente, 8, o Longadder não possui uma API para multiplicação e divisão).
No entanto, quando o número de concorrência não é muito alto, a divisão em várias células também requer a manutenção da célula e da soma, o que não é tão eficiente quanto a implementação do atômico. Longadder usou uma maneira inteligente de resolver esse problema.
Na situação inicial, Longadder e Atomiclong são os mesmos. Somente quando o CAS falhar, o valor será dividido nas células. Cada vez que a falha é feita, o número de células será aumentado. Isso também é eficiente em baixa simultaneidade. Em alta simultaneidade, esse método de processamento "adaptativo" não falhará após atingir um certo número de células, e a eficiência será bastante aprimorada.
Longadder é uma estratégia de trocar espaço pelo tempo.
2. Completefuture
Implementar a interface do conclusão (mais de 40 métodos), a maioria dos quais é usada na programação funcional. E suportar chamadas de streaming
Completefuture é uma versão aprimorada do futuro em Java 8
Implementação simples:
importar java.util.concurrent.completablefuture; classe pública AskThread implementa Runnable {CompletableFuture <Teger> re = null; public AskThread (CompletableFuture <Teger> re) {this.re = re; } @Override public void run () {int myre = 0; tente {myre = re.get () * re.get (); } catch (Exceção e) {} System.out.println (myre); } public static void main (string [] args) lança interruptedException {final CompletableFuture <Teger> futuro = new CompletableFuture <Teger> (); novo thread (novo AskThread (futuro)). Start (); // simular um thread de processo de cálculo de longo prazo.Sleep (1000); // informa o resultado da conclusão futuro.complete (60); }} A coisa mais criticada sobre o futuro é que você deve esperar e verificar se a tarefa foi concluída por si mesmo. No futuro, o tempo para a conclusão da tarefa é incontrolável. A maior melhoria do Firmfuture é que o tempo para a conclusão da tarefa também está aberto.
futuro.complete (60);
Usado para definir o tempo de conclusão.
Execução assíncrona do Firmfuture:
public estático Inteiro Calc (Inteiro para) {tente {// simular um thread de execução longo.sleep (1000); } catch (interruptedException e) {} retornar para * pará; } public static void main (string [] args) lança interruptedException, executionException {final CompletableFuture <TEGER> FUTURO = CONCLUSEBLEFUTURE .Supplyasync (() -> calc (50)); System.out.println (futura.get ()); } CHAMADA DE STRILHAMENTO DE CONCLUSEFUTURE: Public estático Inteiro Calc (Inteiro Para) {Try {// simular um thread de execução longo.sleep (1000); } catch (interruptedException e) {} retornar para * pará; } public static void main (string [] args) lança interruptedException, executionException {completableFuture <Void> fu = completableFuture .Supplyasync (() -> calc (50) .TheNapply ((i) -> integger.ToString (i)). .ThenAcept (System.out :: println); fu.get (); }Combine múltiplos Future Future:
public estático inteiro calc (número inteiro para) {retornar para / 2; } public estático void main (string [] args) lança interruptedException, executionException {completableFuture <Void> fu = completableFuture .Supplyasync (() -> calc (50) .Thencompose ((i) -> completableFuture.supplyasync (() -() ((i) -> completableFuture.supplysync () -> "" "/" ") .ThenCept (System.out :: println); fu.get (); } Esses exemplos se concentram mais em alguns novos recursos do Java 8. Aqui estão alguns exemplos para ilustrar os recursos, por isso não entrarei em profundidade.
O CompletFuture tem pouco a ver com desempenho, mas é mais importante para apoiar a programação funcional e o aprimoramento das funções. Obviamente, a configuração do tempo de conclusão é um destaque.
3. Stampedlock
No artigo anterior, a separação de bloqueio foi mencionada e a importante implementação da separação de bloqueio é ReadWritelock. Stampedlock é uma melhoria do ReadWritelock. A diferença entre StampedLock e ReadWritelock é que o StampedLock acredita que a leitura não deve bloquear as gravações, e Stampedlock acredita que, ao ler e escrever são mutuamente exclusivas, a leitura deve ser relida, em vez de não permitir que o tópico de escrita escreva. Esse design resolve o problema de escrever fome no fio ao ler mais e escrever menos.
Portanto, o StampedLock é uma melhoria que tende a escrever threads.
Exemplo de StampedLock:
importar java.util.concurrent.locks.stampedlock; public class Point {private duplo x, y; Final Private Final Stampedlock SL = new SampedLock (); Void Move (Deltax duplo, Double Deltay) {// Um método bloqueado exclusivamente carimbo longo = sl.Writelock (); tente {x += deltax; y += deltay; } finalmente {sl.unlockwrite (carimbo); }} dupla distanceFromOrigin () {// Um método de leitura-somente longa carimbo = sl.TryOptimisticRead (); duplo currentx = x, currenty = y; if (! tente {currentx = x; currenty = y; } finalmente {sl.unlockread (carimbo); }} retornar math.sqrt (currentx * currentX + currenty * currenty); }}O código acima simula o tópico de escrita e o tópico de leitura. O StampedLock verifica se é mutuamente exclusivo de acordo com o carimbo. Ao escrever um carimbo uma vez, aumenta um certo valor.
TryOptimisticRead ()
É a situação em que a leitura e a escrita não são mutuamente exclusivas, como mencionado.
Toda vez que você lê um tópico, você primeiro fará um julgamento
if (! sl.validate (carimbo))
No Validate, primeiro verificará se há uma redação de escrita e, em seguida, determinará se o valor de entrada é o mesmo que o carimbo atual, ou seja, determine se o thread de leitura lerá os dados mais recentes.
Se houver uma escrita de escrita ou o valor do carimbo for diferente, o retorno falhará.
Se o julgamento falhar, é claro que você pode tentar lê -lo repetidamente. No código de exemplo, não tem permissão para tentar lê -lo repetidamente, mas usa o bloqueio de otimismo para ser degenerado em bloqueios de leitura comuns para lê -lo. Esta situação é um método de leitura pessimista.
carimbo = sl.readlock ();
Ideia de implementação do StampedLock:
CLH Spin Lock: Quando o aplicativo de bloqueio falha, o thread de leitura não será suspenso imediatamente. Uma fila de thread em espera será mantida na fechadura. Todos os tópicos que se aplicam a bloqueios, mas nenhum threads bem -sucedido é gravado nesta fila. Cada nó (um nó representa um thread) salva um bit trancado para determinar se o encadeamento atual liberou o bloqueio. Quando um thread tenta adquirir um bloqueio, ele obtém o nó da cauda da fila de espera atual como seu nó antecessor. E use códigos como os seguintes para determinar se o nó premiado liberou com sucesso o bloqueio
enquanto (pred.locked) {
}
Esse loop deve esperar que o nó anterior libere o bloqueio, para que o encadeamento atual não seja suspenso pelo sistema operacional, melhorando assim o desempenho.
Obviamente, não haverá giros sem fim, e o fio será suspenso após várias rodadas.