A menudo hay algunas tareas en el proyecto que deben ejecutarse de manera asincrónica (enviada al grupo de subprocesos) para ejecutarse, mientras que el hilo principal a menudo necesita conocer los resultados de la ejecución asincrónica. ¿Qué debemos hacer en este momento? Es imposible lograr con Runnable, necesitamos usar la llamada para leer el siguiente código:
import java.util.concurrent.callable; import java.util.concurrent.executionException; import java.util.concurrent.executorservice; import java.util.concurrent.executors; import java.util.concurrent.future; public addsable implements <intreger> {private intent a, by, be, by, by, by, be, by, be, by, beathin a, by, be, by, be, by, beath. public addtask (int a, int b) {this.a = a; this.b = b; } @Override public Integer Call lanza una excepción {resultado entero = a + b; resultado de retorno; } public static void main (string [] args) lanza interruptedException, ExecutionException {EjecutorService Ejecutor = Ejecutors.newsingLethreadExecutor; // JDK ha regresado hasta ahora y son instancias de FutureTask Future <Integer> Future = Ejecutor.submit (nueva addTask (1, 2)); Resultado entero = futuro.get; // Solo cuando se completa el estado del futuro (futuro.isdone = true), el método get se devolverá}} Aunque podemos darnos cuenta del requisito de obtener resultados de ejecución asincrónicos, descubrimos que este futuro en realidad no es útil porque no proporciona un mecanismo de notificación, lo que significa que no sabemos cuándo se completará el futuro (si necesitamos sondear isDone () para juzgar, parece que no es necesario usar esto). Eche un vistazo al método de interfaz de java.util.concurrent.future.future:
Interfaz pública Future <V> {boolean Cancel (boolean MayInterruptUrning); booleano iscancelled; Boolean Isdone; V Get Throws InterruptedException, ExecutionException; V Get (Tiempo de espera largo, unidad de tiempo de tiempo) lanza interruptedException, ExecutionException, TimeOutException;} De esto podemos ver que el mecanismo futuro de JDK en realidad no es fácil de usar. Si puede agregar un oyente a este futuro y dejar que notifique al oyente cuando se complete, será más fácil de usar, al igual que la siguiente ifuture:
paquete futuro; import java.util.concurrent.cancellationException; import java.util.concurrent.future; import java.util.concurrent.timeunit;/*** El resultado de una operación asincrónica. * * @Author LIXIAOHUI * @param <v> Tipo de parámetro del resultado de ejecución */interfaz pública ifuture <v> extiende el futuro <v> {boolean issuccess; // Si V GetNow es exitoso; // devuelve el resultado inmediatamente (independientemente de si el futuro está en el estado completado) causa tirada; // El motivo de la falla de ejecución es cancelable; // ¿Puedo cancelar ifuture <v> esperar tiros interruptedException; // Esperando la finalización futura Boolean espera (Long Timeoutmillis) arroja interruptedException; // Tiempo de espera de espera para futuros finalización Boolean espera (tiempo de espera largo, tiempo de tiempo de tiempo de tiempo) lanza interruptedException; Ifuture <V> awaitUnInterruptiblemente; // Esperando la finalización futura, sin interrupción boolean en espera de interrupción (tiempo de tiempo de espera largo); // tiempo de espera espera para finalizar la futura, sin respuesta de interrupción boolean en espera de interrupción (tiempo de espera largo, tiempo de tiempo de tiempo de tiempo); Ifuture <v> addListener (ifutureListener <v> l); // Cuando se complete el futuro, estos oyentes agregados serán notificados ifuture <v> remelistener (ifutureListener <v> l); } A continuación, implementemos esta ifuture juntos. Antes de esto, explicaremos el método Object.Wait, Object.notifyall, porque el núcleo del "��" original de toda la implementación futura son estos dos métodos. Echa un vistazo a la explicación en JDK:
Objeto de clase pública { /** * hace que el hilo actual espere hasta que otro hilo invoque el método * {@link java.lang.object#notify} o el método * {@link java.lang.object#notifyall} para este objeto. * En otras palabras, este método se comporta exactamente como si simplemente * realice la llamada {@code Wait (0)}. * Después de llamar a este método, el hilo actual liberará el bloqueo del monitor de objeto y renunciará a los derechos de uso de la CPU. Hasta que otro hilo llame a notificar/ notifyall */ public Final Void Wait lanza interruptedException {Wait (0); } /*** Rementa todos los hilos que están esperando en el monitor de este objeto. A * hilo espera en el monitor de un objeto llamando a uno de los métodos * {@code Wait}. * <p> * Los hilos despiertos no podrán continuar hasta que el hilo actual * renuncie al bloqueo de este objeto. Los hilos despiertos * competirán de la manera habitual con cualquier otro hilo que pueda * competir activamente para sincronizar en este objeto; Por ejemplo, * los hilos despiertos no disfrutan de un privilegio o desventaja confiable al ser el siguiente hilo para bloquear este objeto. */ Public Final Native NotifyAll;} Después de saber esto, tenemos la idea de implementar el futuro por nosotros mismos. Cuando el hilo llama a una serie de métodos como ifuture.await, si no se ha completado el futuro, llame al futuro. Cuando otros hilos establecen el futuro en el estado de finalización (tenga en cuenta que el estado de finalización aquí incluye final normal y final anormal), el futuro. No debe llamarse el método para despertar los hilos que estaban en el estado de espera debido a que llama al método de espera. La implementación completa es la siguiente (el código no debería ser difícil de entender. Me refiero al mecanismo futuro de Netty. Si está interesado, puede consultar el código fuente de Netty):
paquete futuro; import java.util.collection; import java.util.concurrent.cancellationException; import java.util.concurrent.CopyOnwriteArrayList; import java.util.concurrent.ExecutionException; import java.util.concurrent.timeunit; import java.util..concurrent.TimeOut./** ** ** ** ** ** <pre> * en el final normal, si el resultado de la ejecución no es nulo, entonces el resultado es el resultado de la ejecución; Si el resultado de la ejecución es nulo, entonces result = {@link abstractFuture#situtor_signal} * Cuando la excepción finaliza, el resultado es una instancia de {@link causa tholder}; Si la excepción termina debido a la cancelación, el resultado es una instancia de {@link cancelationException}, de lo contrario, es una instancia de otras excepciones * Las siguientes situaciones hará que la operación asíncrona se transfiera desde el estado inacabado al estado completado, el método de notificación de notificación se denomina cuando ocurran las siguientes situaciones: * <ul> * * <li> <li> Cuando la operación asíncrona termina normalmente (método setSuccess) </li> * <li> Cuando la operación asíncrona finaliza anormalmente (método setFailure) </li> * </ul> * </pre> * * * @author lixiaohui * * @param <v> * tipo de activo de ejecución asíncrono */public abstracts freuture <V> <V> resultado del objeto volátil; // debe garantizarse para que sea visibilidad/ *** Conjunto de oyente*/ Collection Protected <ifuteReListener <v>> oyentes = new CopyOnwriteArrayList <ifuteReListener <v>>; / *** Cuando el resultado de ejecución normal de la tarea es nula, es decir, cuando el cliente llama {@link abstractFuture#setSuccess (null)},* El resultado hace referencia al objeto*/ static final static final stitsignalsign_signal = new Successignal; @Override public boolean Cancel (boolean MayInterruptiNning) {if (isDone) {// return false no se puede cancelar; } sincronizado (this) {if (isDone) {// Double check return false; } result = New CauseHolder (New CancellationException); notificar todo; // isDone = true, notifique al hilo que espera en la espera en el objeto} notifyListeners; // notifica al oyente que la operación asíncrona se ha completado return treal; } @Override public boolean isCancellable {return resultado == null; } @Override public boolean isCancelled {return resultado! = NULL && resultado instancia de causa tolda && ((causa titular) resultado). CAUSA INSTACEOF CancellationException; } @Override public boolean isDone {return resultado! = Nulo; } @Override public v Get Throws InterruptedException, ExecutionException {espera; // Espere el resultado de la ejecución, Cause de lanzamiento = Causa; if (causa == null) {// No se produjo una excepción, la operación asíncrona terminó normalmente return getNow; } if (causar instancia de cancelationException) {// La operación asíncrona fue cancelada de lanzar (cancelationException) causa; } Lanzar una nueva ExecutionException (causa); // Otras excepciones} @Override public v Get (Tiempo de espera largo, unidad de tiempo de tiempo) arroja interruptedException, ExecutionException, TimeOutException {if (Await (TimeOut, Unit)) {// Tiempo de espera esperando el resultado de la ejecución que se puede hacer una causa = causa = Causa; if (causa == null) {// No se produjo una excepción, la operación asíncrona terminó normalmente return getNow; } if (causa instancia de cancelación dexceptación) {// La operación asíncrona fue cancelada de lanzamiento de lanzamiento (cancelationException) causa; } Lanzar una nueva ExecutionException (causa); // Otras excepciones} // El momento aún no ha terminado, lanzando una excepción de tiempo de espera, lanze una nueva TimeOutException; } @Override public boolean issuccess {return resultado == nulo? falso: } @SupplesSwarnings ("sin verificar") @Override public v getNow {return (v) (resultado == striture_signal? Null: resultado); } @Override public showleable Cause {if (resultado! = Null && resultado instanceo de causa holdicer) {return ((causa tholder) resultado) .Cause; } return null; } @Override public Ifuture <V> addListener (ifuTureListener <v> oyente) {if (oyente == null) {tire nueva nullpointerException ("oyente"); } if (isDone) {// Si ha completado NotifyListener (oyente); devolver esto; } sincronizado (this) {if (! isDone) {oyentes.add (oyente); devolver esto; }} notifyListener (oyente); devolver esto; } @Override public ifuture <V> removeListener (ifuTureListener <v> oyente) {if (oyente == null) {tirar nueva nullPointerException ("oyente"); } if (! Isdone) {oyentes.remove (oyente); } devolver esto; } @Override public Ifuture <V> ALear tiros interruptedException {return await0 (true); } private ifuture <v> await0 (boolean interruptable) lanza interruptedException {if (! isDone) {// Si se ha completado, se devolverá directamente // si el terminal está permitido e interrumpido, se lanzará una excepción de interrupción si (interrumpible && Thread.interrupted) {Drow New InterruptedException ("hilo" hilt ". interrumpido "); } boolean interrumped = false; sincronizado (this) {while (! isDone) {try {espera; // libere el bloqueo e ingrese el estado de espera, espere a que otros hilos llamen al método del objeto notificar/notifyall} capt (interruptedException e) {if (interruptable) {lanzar e; } else {interrupted = true; }}}}} if (interrumped) {// ¿Por qué necesitamos establecer el indicador de interrupción aquí? Porque después de regresar del método de espera, el indicador de interrupción se borra, // reinicie aquí para que otros códigos sepan que se interrumpe aquí. Thread.CurrentThread.interrupt; }} devuelve esto; } @Override public boolean espera (Long Timeoutmillis) lanza interruptedException {return await0 (timeUnit.milliseconds.tonanos (timeoutmillis), verdadero); } @Override public boolean espera (tiempo de espera largo, unidad de tiempo de tiempo) lanza interruptedException {return await0 (unit.tonanos (tiempo de espera), verdadero); } booleano privado await0 (larga tiempo de espera, boolean interruptable) lanza interruptedException {if (isDone) {return true; } if (timeOutNanos <= 0) {return isDone; } if (Interruptable && Thread.interrupted) {Throw New InterruptedException (toString); } Long StartTime = TimeOutNanos <= 0? 0: System.Nanotime; long waittime = timeOutnanos; booleano interrumpido = falso; intente {sincronizado (this) {if (isDone) {return true; } if (waitTime <= 0) {return isDone; } para (;;) {try {Wait (WaitTime / 1000000, (int) (waittime % 1000000)); } capt (interruptedException e) {if (interruptable) {lanzar e; } else {interrupted = true; }} if (isDone) {return true; } else {waitTime = timeOutNanos - (system.nanotime - starttime); if (waitTime <= 0) {return isDone; }}}}}} Finalmente {if (interrumped) {thread.currentThread.interrupt; }}} @Override public Ifuture <V> awaitUnInterruptiblemente {try {return await0 (false); } Catch (InterruptedException e) {// Si se lanza una excepción aquí, no se puede manejar, tire nuevo java.lang.InternalError; }} @Override public boolean awaitUnInterruptiblemente (Long TimeoutMillis) {try {return await0 (timeUnit.milliseConds.tonanos (timeoutmillis), falso); } Catch (InterruptedException e) {tire nuevo java.lang.internalError; }} @Override public boolean awaitUnInterruptible (Tiempo de espera largo, unidad de tiempo de tiempo) {try {return await0 (unit.tonanos (tiempo de espera), falso); } Catch (InterruptedException e) {tire nuevo java.lang.internalError; }} protegido ifuture <v> setFailure (causa de lanzamiento) {if (setFailure0 (causa)) {notifyListeners; devolver esto; } tirar nueva ilegalStateException ("Completa ya:" + esto); } private boolean setFailure0 (causa de lanzamiento) {if (isDone) {return false; } sincronizado (this) {if (isDone) {return false; } result = New Causeholder (causa); notificar todo; } return verdadero; } protegido ifuture <v> setSuccess (resultado del objeto) {if (setSuccess0 (resultado)) {// notifyListeners después de configurar con éxito; devolver esto; } tirar nueva ilegalStateException ("Completa ya:" + esto); } private boolean setSuccess0 (resultado del objeto) {if (isDone) {return false; } sincronizado (this) {if (isDone) {return false; } if (result == null) {// El resultado de la ejecución normal de la operación asíncrona es nulo this.result = strites_signal; } else {this.result = resultado; } notifyall; } return verdadero; } private void notifyListeners {para (ifutureListener <v> l: oyentes) {notifyListener (l); }} private void notifyListener (ifutureListener <v> l) {try {l.operationCompleted (this); } catch (Exception e) {E.PrintStackTrace; }} Clase estática privada SuccessSignal {} privada de la clase final estática Causeholder {Final Throwable Cause; Causeholder (causa lanzable) {this.Cause = Cause; }}} Entonces, ¿cómo usar esto? Con la implementación del esqueleto anterior, podemos personalizar varios resultados asincrónicos. La siguiente es una tarea retrasada:
paquete futuro.test; import future.ifuture; import future.ifutureReListener;/** * Delay Addition * @author lixiaohui * */public class retrasyAdder {public static void main (String [] args) {new Deletadder.add (3 * 1000, 1, 2) .addlistener (New ifutureNistener <integer> { @ @ @ @@override OperationCompleted (ifuture <integer> futuro) lanza la excepción {System.out.println (Future.getNow); } / *** Adición de retraso* @param Delay Duración Duración Millisegunds* @param una adición* @param b adición* @return asynchronous result* / public retrasyAdditionFuture add (Long Delay, int a, int b) {DelayAdditionFuture Future = New DelayDitionFuture; nuevo hilo (nuevo retrasoAdditionTask (demora, a, b, futuro)). Inicio; regresar futuro; } La clase privada de retrasoAdditionTask implementa Runnable {private largo retraso; privado int a, b; FUTURO DE LA DELATRA DE LA RETRACIÓN PRIVADA; Public DelayAdditionTask (Long Delay, int a, int B, DelayAdditionFuture Future) {super; this.delay = retraso; esto.a = a; this.b = b; this.future = futuro; } @Override public void run {try {thread.sleep (demora); Entero i = a + b; // TODO Aquí está el futuro establecido en el estado de finalización (la ejecución normal se completa) Future.setsuccess (i); } catch (interruptedException e) {// TODO Aquí está el futuro establecido en el estado de finalización (la excepción se completa) Future.setFailure (E.getCause); }}}} paquete futuro.test; import future.abstractFuture; import future.ifuture; // Simplemente exponga dos métodos al retraso de la clase pública externa, lafuture extiende lafuture de los abstracts <integer> {@Override public Ifuture <Integer> setSuccess (resultado del objeto) {retorno super.setsucess (resultado); } @Override public ifuture <Integer> setFailure (causa de lanzamiento) {return super.setFailure (causa); }} Puede ver que el cliente no necesita preguntar activamente si el futuro está completado, pero automáticamente devolverá el método OperationCompleted cuando se complete el futuro. El cliente solo necesita implementar la lógica en la devolución de llamada.
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.