Muitas vezes, existem algumas tarefas no projeto que precisam ser executadas de forma assíncrona (enviadas ao pool de threads) a serem executadas, enquanto o thread principal geralmente precisa saber os resultados da execução assíncrona. O que devemos fazer neste momento? É impossível de alcançar com o Runnable, precisamos usar o Callable para ler o seguinte código:
importar java.util.Concurrent.Callable; importar java.util.concurrent.executionException; importar java.util.concurrent.executorService; importar java.util.CoCurrent.Executores; importar java.util.concurrent.future; public addtask (int a, int b) {this.a = a; this.b = b; } @Override Public Integer Call lança Exceção {Inteiro resultado = a + b; resultado de retorno; } public static void main (string [] args) lança interruptedException, ExecutionException {ExecutSerService Execor (executores.NewsingleThreadExecutor; // JDK retornou até agora e são instâncias de FutureTask FUTURO <TEGER> FUTURO = Executor.Submit (new Addtask (1, 2)); Inteiro resultado = futuro.get; // somente quando o status do futuro for concluído (futuro.isdone = true), o método get retornará}} Embora possamos perceber o requisito de obter resultados de execução assíncronos, descobrimos que esse futuro não é útil porque não fornece um mecanismo de notificação, o que significa que não sabemos quando o futuro será concluído (se precisarmos pesquisar Isdone () para julgar, parece que não há necessidade de usar isso). Dê uma olhada no método da interface de java.util.concurrent.future.future:
interface pública Future <V> {cancelamento boolean (boolean mayinterruptifrunning); Boolean iscancelada; Isdone booleano; V Get Throws InterruptedException, ExecutionException; V Get (tempo limite de longa data, unidade timeunit) lança interruptedException, executionException, timeoutException;} A partir disso, podemos ver que o mecanismo futuro do JDK não é fácil de usar. Se você pode adicionar um ouvinte a este futuro e deixá -lo notificar o ouvinte quando estiver concluído, será mais fácil de usar, assim como o seguinte ifuture:
pacote futuro; importar java.util.concurrent.cancellationException; importar java.util.concurrent.future; importar java.util.concurrent.timeunit;/*** o resultado de uma operação assíncrona. * * @author lxiaohui * @param <V> Tipo Parâmetro do resultado da execução */interface pública ifuture <v> estende o futuro <V> {boolean issuccess; // se V GetNow é bem -sucedido; // retorna o resultado imediatamente (independentemente de o futuro estar no estado concluído) causa arremessada; // O motivo da falha de execução é cancelável; // Posso cancelar o ifuture <V> Aguarda os lançamentos interrompedException; // aguardando a conclusão futura boolean aguarda (longa tempo de limpeza) lança interruptedException; // Tempo limite Aguarde a conclusão futura booleana aguarda (tempo limite de longo prazo, timeunidade do tempo) lança interruptedException; Ifuture <V> Aguarda // aguardando a conclusão futura, nenhuma interrupção booleana aguarda interruptível (tempo de tempo de tempo de tempo de longa data); // Tempo limite aguarda a conclusão futura, nenhuma resposta de interrupção Ifuture <V> addListener (ifutureListener <V> l); // Quando o futuro for concluído, esses ouvintes adicionados serão notificados ifuture <V> removeListener (ifutureListener <V> l); } Em seguida, vamos implementar esse ifuture juntos. Antes disso, explicaremos o objeto. Dê uma olhada na explicação no JDK:
classe pública Objeto { /** * faz com que o thread atual aguarde até que outro thread invoce o método * {@link java.lang.object#notify} ou o método * {@link java.lang.object#notifyall} para este objeto. * Em outras palavras, esse método se comporta exatamente como se simplesmente * executasse a chamada {@code wait (0)}. * Depois de chamar esse método, o encadeamento atual liberará o bloqueio do monitor de objetos e desistirá dos direitos de uso da CPU. Até que outro tópico chama notificar/ notifyall */ public Final Void Wait Throws InterruptEdException {wait (0); } /*** acorda todos os threads que aguardam o monitor deste objeto. A * Thread espera no monitor de um objeto chamando um dos métodos * {@code wait}. * <p> * Os threads despertados não poderão prosseguir até que o thread atual * renuncie à trava nesse objeto. Os threads despertados * competirão da maneira usual com quaisquer outros threads que possam * competir ativamente para sincronizar nesse objeto; Por exemplo, * os threads despertados não desfrutam de privilégio ou desvantagem confiáveis em * ser o próximo thread a bloquear esse objeto. */ Public Final Native Void NotifyAll;} Depois de saber disso, temos uma idéia de implementar o futuro por nós mesmos. Quando o tópico chama uma série de métodos como o ifuture.await, se o futuro não tiver sido concluído, ligue para o método do futuro. Quando outros threads definem futuro para o estado de conclusão (observe que o estado de conclusão aqui inclui fim normal e final anormal), o futuro. Não é necessário ser chamado para acordar os threads que estavam no estado de espera por causa do método de espera. A implementação completa é a seguinte (o código não deve ser difícil de entender. Consultei o mecanismo futuro da rede. Se você estiver interessado, pode conferir o código -fonte da Netty):
pacote futuro; importar java.util.Collection; importar java.util.concurrent.cancellationException; importar java.util.concurrent.copyonWriteArrayList; import Java.util.Concurrent.executionException; import java.util.Concurent.TimeUnit.memport.port.mport.port.execution; <pre> * No final normal, se o resultado da execução não for nulo, o resultado será o resultado da execução; Se o resultado da execução for nulo, resulte = {@link abstractfuture#succcess_signal} * Quando a exceção termina, o resultado é uma instância de {@link cotamolder}; Se a exceção terminar devido ao cancelamento, o resultado é uma instância de {@link cancellationException}; caso contrário, é uma instância de outras exceções * As seguintes situações farão com que a operação assíncrona seja transferida da operação inacessada: *> *> * <li> O método notificado é chamado quando as seguintes situações ocorrem: * </li> * <li> Quando a operação assíncrona termina normalmente (método do conjunto de sucrição) </li> * <li> Quando a operação assíncrona termina de forma anormal (Método SetFailure) </li> * </ul> * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Ifuture <V> {resultado do objeto volátil protegido; // precisa ser garantido para ser visibilidade/ *** Set de ouvinte*/ coleção protegida <ifutureListener <V>> ouvintes = new copyonWriteArrayList <ifutureListener <V>>; / *** Quando o resultado normal da execução da tarefa é nulo, ou seja, quando o cliente chama {@link abstractFuture#SetSuccess (null)},* Resultado Refere -se o objeto*/ private Static Final SuccessSignal SUCCESSE_SIGNA = NEW SUCCESTSIGNAL; @Override public boolean cancel (boolean mayInterruptifrunning) {if (isdone) {// return false não pode ser cancelado; } sincronizada (this) {if (iSdone) {// Verificar dupla Return false; } resultado = new Kayholder (novo CancellationException); notificar todos; // isdone = true, notifique o thread aguardando a espera no objeto} notifyListeners; // Notifique o ouvinte de que a operação assíncrona foi concluída, retorna true; } @Override public boolean iscancellable {return resultado == null; } @Override public boolean iscancelled {return resultado! = Null && Resultado Instância do co -holdler && ((cotamolder) resultado) .Cause Instância de cancelationException; } @Override public boolean iSdone {return resultado! = Null; } @Override public V Get Throws InterruptEdException, ExecutionException {Await; // Aguarde pelo resultado da execução causável causa = causa; if (causa == null) {// Nenhuma exceção ocorreu, a operação assíncrona terminou normalmente retornar GetNow; } if (causa instanceof cancellationException) {// a operação assíncrona foi cancelada arremesso (cancelationException) causa; } lançar nova execução Exception (causa); // Outras exceções} @Override public V Get (tempo limite de longa data, unidade de unidade de tempo) lança interruptedException, executionException, timeoutException {if (aguarda (tempo limite, unidade)) {// tempo limite aguardando o resultado da execução causável causa = causa; if (causa == null) {// Nenhuma exceção ocorreu, a operação assíncrona terminou normalmente retornar GetNow; } if (causa a instância do cancellationException) {// A operação assíncrona foi cancelada (cancelationException) causa; } lançar nova execução Exception (causa); // Outras exceções} // O tempo ainda não terminou, lançando uma exceção de tempo limite, lançar uma nova timeoutException; } @Override public boolean issuccess {return resultado == null? FALSO:! (Instância do resultado do co -holdler); } @Suppresswarnings ("desmarcado") @Override public v getNow {return (v) (resultado == success_signal? Null: resultado); } @Override Public Throwable Causa {if (Result! } retornar nulo; } @Override public ifuture <V> addListener (ifutureListener <V> ouvinte) {if (ouvinte == null) {lança new nullPointerException ("ouvinte"); } if (isdone) {// se você concluiu o notifyListener (ouvinte); devolver isso; } sincronizado (this) {if (! isdone) {ouvintes.add (ouvinte); devolver isso; }} notifyListener (ouvinte); devolver isso; } @Override public ifuture <V> removeListener (ifutureListener <V> ouvinte) {if (ouvinte == null) {lança new nullPointerException ("ouvinte"); } if (! isDone) {ouvintes.remove (ouvinte); } retornar isso; } @Override public ifuture <V> Aguarda lança interruptedException {return wait0 (true); } Private ifuture <V> Await0 (Boolean Interruptable) lança interruptEdException {if (! isDone) {// Se tiver sido concluído, será retornado diretamente // se o thread interrupto e interrupto (Thread) é que o thread (thread) é permitido (thread) e interrupto (thread) (Thread) e interrupto (thread. interrompido. "); } booleano interrompido = false; sincronizado (this) {while (! isdone) {try {wait; // Libere o bloqueio e digite o estado de espera, aguarde outros threads para chamar o método Notify/NotifyAll do objeto} Catch (interruptedException e) {if (interrompível) {throw e; } else {interromped = true; }}}}} if (interrompido) {// Por que precisamos definir o sinalizador de interrupção aqui? Porque depois de retornar do método de espera, o sinalizador de interrupção é limpo, // redefinir aqui para que outros códigos saibam que ele é interrompido aqui. Thread.CurrentThread.Interrup; }} Retorne isso; } @Override public boolean Await (TimeoutMillis LongMillis) lança interruptedException {return wait0 (timeunit.milliseconds.tonanos (timeoutmillis), true); } @Override public boolean Await (Timeout longo, unidade de unidade de tempo) lança interruptedException {return wait0 (unit.tonanos (timeout), true); } Private boolean Await0 (Timeoutnanos longo, interrompível booleano) lança interruptedException {if (isDone) {return true; } if (timeoutnanos <= 0) {return isDone; } if (interruptável && thread.interrupted) {throw new InterruptEdException (tostring); } long startTime = timeoutnanos <= 0? 0: System.Nanotime; Waittime longo = timeoutnanos; interrompido booleano = false; tente {sincronizado (this) {if (iSdone) {return true; } if (waittime <= 0) {return isDone; } para (;;) {try {wait (waittime / 1000000, (int) (waittime % 1000000); } catch (interruptedException e) {if (interruptável) {tiro e; } else {interromped = true; }} if (isDone) {return true; } else {waittime = timeoutnanos - (System.nanotime - startTime); if (waittime <= 0) {return isDone; }}}}}} finalmente {if (interrompido) {thread.currentThread.interrupt; }}} @Override public ifuture <V> Aguarda -de -interruptivelmente {Try {return wait0 (false); } catch (interruptedException e) {// Se uma exceção for lançada aqui, ela não pode ser tratada, jogue new java.lang.internalError; }} @Override public boolean AwaitunInterruptível (Timeoutmillis longo) {Try {return wait0 (timeUnit.millisEconds.tonanos (timeoutmillis), false); } catch (interruptedException e) {tiro novo java.lang.internalError; }} @Override public boolean AwaitunInterruptível (tempo limite de longa data, unidade de timeUnit) {try {return wait0 (unit.tonanos (timeout), false); } catch (interruptedException e) {tiro novo java.lang.internalError; }} ifuture protegido <V> setFailure (causa de arremesso) {if (setFailure0 (causa)) {notifyListeners; devolver isso; } lançar new ilegalStateException ("Complete já:" + this); } private boolean setFailure0 (causa de arremesso) {if (isdone) {return false; } sincronizado (this) {if (iSdone) {return false; } resultado = novo cotamolder (causa); notificar todos; } retornar true; } ifuture protegido <V> SetSuccess (resultado do objeto) {if (setSuccess0 (resultado)) {// notifyListeners após definir com sucesso; devolver isso; } lançar new ilegalStateException ("Complete já:" + this); } Setsucces de booleano privado (resultado do objeto) {if (iSdone) {return false; } sincronizado (this) {if (iSdone) {return false; } if (resultado == null) {// O resultado da execução normal da operação assíncrona é nula this.result = success_signal; } else {this.result = resultado; } notifyAll; } retornar true; } private void notifyListeners {for (ifutureListener <v> l: ouvintes) {notifyListener (l); }} private void notifyListener (ifutureListener <v> l) {try {l.operationCompleted (this); } catch (Exceção e) {e.printStackTrace; }} classe estática privada SUCCESTSIGNAL {} classe estática privada de estática Final Kayholder {Final Throwable Causa; Oland Holders (causa jogável) {this.cause = causa; }}} Então, como usar isso? Com a implementação do esqueleto acima, podemos personalizar vários resultados assíncronos. A seguir, é uma tarefa atrasada:
pacote futuro.test; importar futuro.ifuture; importar futuro.IFutureListener;/** * adição de atraso * @author lixiaohui * */public class AtardAdder {public static void main (string [] args) {new AtardAdder.add (3 * 1000, 1, 2) .Addlister (newTurEnist. OperationCompleted (ifuture <Teger> Future) lança exceção {System.out.println (FUTURO.GETNOW); } / *** adição de atraso* @param atraso duração Duração milissegundos* @param uma adição* @param b adição* @return resultado assíncrono* / public teltoaddditionfuture add (atraso longo, int a, int b) {deLeadAdditionFuture Future = new timeAdditionFuture; novo thread (new AtardAdditionTask (atraso, a, b, futuro)). Iniciar; retornar futuro; } classe privada timeadditionTask implementa Runnable {private Longo Atraso; privado int a, b; Atraso privado Futuro do Future; Public AtardAdditionTask (Longo Atraso, Int A, Int B, DelayAdditionFuture Future) {Super; this.Delay = atraso; this.a = a; this.b = b; this.future = futuro; } @Override public void run {try {thread.sleep (atraso); Número inteiro i = a + b; // TODO Aqui está o conjunto futuro para o status de conclusão (execução normal é concluída) FUTURO.SESTUCESS (i); } catch (interruptedException e) {// todo aqui é o conjunto futuro para o status de conclusão (exceção é concluída) futura.setFailure (e.getCausa); }}}} pacote futuro.test; importar futuro.abstractfuture; importar o futuro.Ifuture; // apenas exponha dois métodos à classe pública externa de atraso, estende o abstratoFuture <Teger> {@Override public ifuture <Teger> Setsuccess (object resultado) {Retur.SetsUSCSCCSCEN (ResultsUccess) {Retur.SetSucss; } @Override public ifuture <Teger> setFailure (causa de arremesso) {return super.setFailure (causa); }} Você pode ver que o cliente não precisa perguntar ativamente se o futuro está concluído, mas ligará automaticamente de volta o método da Operação Completo quando o futuro for concluído. O cliente só precisa implementar a lógica no retorno de chamada.
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.