Amigos que usaram pacotes de simultaneidade Java podem estar familiarizados com o futuro (interface). O futuro é suportado diretamente no nível de sintaxe em alguns idiomas de domínio (como Alice ML).
Aqui, vamos tomar java.util.concurrent.future como exemplo para falar brevemente sobre o método de trabalho específico do futuro. O próprio objeto futuro pode ser considerado como uma referência explícita, uma referência aos resultados do processamento assíncrono. Devido à sua natureza assíncrona, o objeto que ele referências pode não estar disponível no início da criação (por exemplo, ele ainda está em operação, transmissão de rede ou espera). No momento, se o fluxo do programa que obtém o futuro não estiver com pressa de usar o objeto referenciado pelo futuro, ele poderá fazer o que quiser. sejam duas situações:
Espero ver este objeto disponível e concluir alguns processos de acompanhamento relacionados. Se estiver realmente indisponível, você também pode inserir outros processos de ramificação.
"Sem você, minha vida perderá seu significado, então mesmo que o mar se fosse, vou esperar por você." -tempo)
Para o caso anterior, você pode determinar se o objeto referenciado está pronto chamando Future.isdone () e fazer processamento diferente;
Obtenha (tempo limite de longa data, unidade de unidade de tempo) aguarda que o objeto esteja pronto por bloqueio síncrono. Se o tempo de execução real é bloqueado ou retornado imediatamente depende do tempo de chamada de get () e da ordem do objeto pronta.
Simplificando, o modo futuro pode atender às necessidades de concorrência orientadas a dados em processos contínuos, não apenas obtendo melhorias de desempenho na execução simultânea, mas também simplicidade e elegância de processos contínuos.
Comparação com outros padrões de design simultâneos
Além do futuro, outros padrões de design de simultaneidade comuns incluem "orientado por retorno de chamada (em ambiente multi-thread)", "Mensagem/evento orientado (no modelo de ator)", etc.
O retorno de chamada é o modo de simultaneidade assíncrona mais comum, que possui alto imediatismo e design de interface simples. Mas, em comparação com o futuro, suas desvantagens também são muito óbvias. Primeiro, os retornos de chamada em ambientes multithread são geralmente executados no thread do módulo que aciona o retorno de chamada, o que significa que os problemas de exclusão mútua devem ser considerados ao escrever métodos de retorno de chamada; Executar retornos de chamada para aplicativos de usuário, que também são relativamente inseguros, porque você não pode determinar quanto tempo levará ou que exceções ocorrerá, o que pode afetar indiretamente o imediatismo e a confiabilidade deste módulo; Sequência. Portanto, a interface de retorno de chamada é adequada para cenários em que apenas tarefas simples precisam ser concluídas em um retorno de chamada e não precisa ser combinado com outros processos.
As desvantagens dos modos de retorno de chamada acima são exatamente os pontos fortes do futuro. Como o uso do futuro é incorporar naturalmente os drivers de dados assíncronos em processos seqüenciais, você não precisa considerar o Thread MUTEX problemas. ser mencionado abaixo "Futuro preguiçoso"). Por outro lado, os módulos que fornecem interfaces futuras não precisam se preocupar com problemas de confiabilidade, como interfaces de retorno de chamada e seu potencial impacto imediato nesse módulo.
Outro padrão de design simultâneo comum é "Mensagem (Evento) orientada", que geralmente é usada no modelo de ator: o solicitante de serviço envia uma mensagem ao provedor de serviços e continua a executar tarefas subsequentes que não dependem dos resultados do processamento de serviços e depende disso, se você precisar confiar nele. Embora esse controle simultâneo baseado em máquina de estado seja mais adequado para processos seqüenciais de continuidade do que os retornos de chamada, os desenvolvedores precisam cortar o processo contínuo em vários subprocessos específicos do estado de acordo com a chamada do serviço assíncrono, que aumenta artificialmente a complexidade do desenvolvimento. O uso do modo futuro pode evitar esse problema e não precisa quebrar processos contínuos para chamadas assíncronas. No entanto, uma coisa deve ser observada: o método futuro.get () pode bloquear a execução do encadeamento; portanto, geralmente não pode ser incorporado diretamente ao modelo de ator convencional. (O modelo de ator baseado em coroutine pode resolver melhor este conflito)
A flexibilidade do Future também se reflete em sua livre escolha entre sincronização e escolhas assíncronas. as necessidades do processo. Por exemplo, você pode decidir se deve usar essa lacuna para concluir outras tarefas com base no fato de os dados estarem prontos, o que é bastante conveniente para implementar o mecanismo "previsão de ramificação assíncrona".
O derivado do futuro
Além das formas básicas mencionadas acima, o futuro também tem mudanças ricas em derivadas, então aqui estão algumas comuns.
Futuro preguiçoso
Ao contrário do Futuros Gerais, o Futuro Lazoso não começa a preparar ativamente o objeto referenciado no início da criação, mas espera até que o objeto seja solicitado antes de iniciar o trabalho correspondente. Portanto, o futuro preguiçoso em si não se destina a alcançar a simultaneidade, mas leva recursos de computação desnecessários para economizar como ponto de partida, e seu efeito é semelhante ao Lambda/fechamento. Por exemplo, ao projetar certas APIs, pode ser necessário retornar um conjunto de informações e o cálculo de alguns deles pode consumir recursos consideráveis. No entanto, o chamador pode não se preocupar com todas essas informações; portanto, fornecer objetos que exigem mais recursos na forma de futuro preguiçoso pode economizar recursos quando o chamador não precisar usar informações específicas.
Além disso, o futuro preguiçoso também pode ser usado para evitar exclusões mútuas desnecessárias causadas pela aquisição prematura ou bloqueio de recursos.
Promessa
A promessa pode ser considerada como um ramo especial do futuro. Mas a promessa é usada para representar explicitamente cenários em que processos assíncronos não são acionados diretamente pelo chamador de serviço. Por exemplo, o controle de tempo da interface futura, seu processo assíncrono não é acionado pelo chamador, mas pelo relógio do sistema. assinante, mas pelo assinante. Portanto, em comparação com o futuro padrão, a interface da promessa geralmente possui um conjunto extra () ou interface FULFILL ().
Futuro reutilizável
Um futuro regular é único, o que significa que, quando você obtém resultados de processamento assíncronos, o próprio objeto futuro perde seu significado. Mas o futuro especialmente projetado também pode ser reutilizado, o que é muito útil para dados que podem ser alterados várias vezes. Por exemplo, a interface de estilo futuro fornecido pela estrutura de assinatura distribuída do Taobao mencionada acima permite que várias chamadas sejam o método WaitNext () (equivalente ao futuro.get ()). Última chamada. A vantagem desse design é que o usuário da interface pode responder a alterações nos dados de assinatura em qualquer momento adequado, ou simplesmente através de um loop infinito em um tópico independente, além de levar em consideração outras tarefas de tempo, ou até aguardar várias tarefas ao mesmo tempo. Exemplos simplificados são os seguintes:
para (;) {cronograma = getNextScheduledTaskTime (); .}} DoscheduledTask ();} Uso do futuro
Primeiro, vamos listar um código de pensamento em Java.
//: Concurrency/Callabledemo.javaimport java.util.Concurrent.*; importar java.util String Call () {return "Resultado de TaskWithResult" + ID; Novo Arraylist <Future <String>> (); tentar : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : ::::::::::::::::::::::Here :::::::::::::::::::hee :::::::::::::::::heo the : :::::::::::::::::::::::::here ::::::: {// get () blocos até a conclusão: system.out.println (fs.get ()) ; :result of TaskWithResult 0result of TaskWithResult 1result of TaskWithResult 2res ult of TaskWithResult 3result of TaskWithResult 4result of TaskWithResult 5result of TaskWithResult 6result of TaskWithResult 7result of TaskWithResult 8result of TaskWithResult 9*///:~Para explicar o uso do futuro, primeiro, o Método ExecorService Object Exec Submit () para gerar um objeto futuro, que usa o tipo específico do resultado de retorno chamável para parametrizar. Você pode usar o método iSdone () para consultar se o futuro foi concluído. Quando a tarefa é concluída, ela tem um resultado e você pode chamar o método get () para obter o resultado. Você também pode ligar diretamente para get () sem a verificação do ISDONE (). Você pode chamar a função get () com um tempo limite ou ligue para ISDONE () primeiro para ver se a tarefa é concluída e depois ligue para get ().