프로젝트에는 비동기 적으로 실행 해야하는 작업이 종종 있으며 (스레드 풀에 제출) 실행되지만 기본 스레드는 종종 비동기 실행 결과를 알아야합니다. 현재 우리는 무엇을해야합니까? Runnable로 달성하는 것은 불가능합니다. 다음 코드를 읽으려면 Callable을 사용해야합니다.
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 class addtask empless <inteit int a inte a addtask empless <inte a addtask rements. public addtask (int a, int b) {this.a = a; this.b = b; } @override public Integer Call은 예외 {정수 결과 = a + b; 반환 결과; } public static void main (String [] args)은 InterruptedException, executionException {ExecutOrserVice executor = executor.newsingLethreadExecutor; // JDK는 지금까지 돌아 왔으며 FutureTask의 미래의 사례입니다. 정수 결과 = Future.get; // 미래의 상태가 완료된 경우에만 (Future.isdone = true), Get 메소드가 reto}}} 우리는 비동기 실행 결과를 얻는 요구 사항을 깨달을 수 있지만, 우리는이 미래가 알림 메커니즘을 제공하지 않기 때문에 실제로 유용하지 않다는 것을 발견했습니다. 즉, 미래가 언제 완료 될지 알지 못합니다 (우리가 판단하기 위해 isdone ()을 설문해야한다면, 이것을 사용할 필요가 없다고 생각합니다). java.util.concurrent.future의 인터페이스 방법을 살펴보십시오.
공개 인터페이스 미래 <v> {부울 취소 (부울 mayinterruptifrunning); 부울 iscancelled; 부울 isdone; v Get Throws InterruptedException, executionException; v get (긴 타임 아웃, TimeUnit Unit)은 InterruptedException, executionException, timeoutException을 던지는 것입니다.} 이것으로부터 우리는 JDK의 미래 메커니즘이 실제로 사용하기 쉽지 않다는 것을 알 수 있습니다. 이 미래에 리스너를 추가하고 청취자가 완료 될 때 리스너에게 알리도록하면 다음 ifuture와 마찬가지로 사용하기가 더 쉽습니다.
패키지 미래; import java.util.concurrent.cancellationException; import java.util.concurrent.future; import java.util.concurrent.timeUnit;/*** 비동기 작업의 결과. * * @author lixiaohui * @param <v> 실행 결과의 유형 매개 변수 */public interface ifuture <v> 향후 <v> {boolean issuccess; // v getnow가 성공했는지; // 결과를 즉시 반환합니다 (미래가 완성 된 상태에 있는지 여부에 관계없이) 던지기 가능한 원인; // 실행 실패의 이유는 취소 가능합니다. // ifuture를 취소 할 수 있습니까? // 미래의 완료를 기다리는 대기 부울 부울 (Long TimeoutMillis)은 InterruptedException을 던집니다. // TimeOut For Future 완료 대기 Boolean Boolean (긴 타임 아웃, TimeUnit TimeUnit)은 중단 된 예를 던졌습니다. ifuture <v> awaituninterruptibly; // 향후 완성을 기다리고, 중단 없음 부울이 발생하지 않게 (긴 타임 아웃 밀리 스); // 타임 아웃은 향후 완성을 기다립니다. ifuture <v> addlistener (ifuturelistener <v> l); // 미래가 완료되면,이 추가 된 청취자들은 ifuture <v> removelistener (ifuturelistener <v> l)에게 알릴 것입니다. } 다음 으로이 ifuture를 함께 구현합시다. 그 전에는 객체를 설명합니다. Wait, object.notifyall 메소드를 설명합니다. 향후 전체 구현의 원래 핵심은이 두 가지 방법이기 때문입니다. JDK의 설명을 살펴보십시오.
공개 클래스 객체 { /** * 다른 스레드가 다른 스레드가 * {@link java.lang.object#notify} 메소드 또는 * {@link java.lang.object#notifyall} 메소드를 호출 할 때까지 대기 스레드가 대기합니다. 다시 말해,이 메소드는 간단히 * {@code wait (0)}을 수행하는 것처럼 정확하게 동작합니다. *이 메소드를 호출 한 후 현재 스레드는 객체 모니터 잠금 장치를 해제하고 CPU 사용 권한을 포기합니다. 다른 스레드 호출이 Notify/ NotifyAll */ public final void wain throws interruptedException {대기 (0); } /***이 객체의 모니터에서 대기하는 모든 스레드를 깨우십시오. * 스레드는 * {@code 대기} 메소드 중 하나를 호출하여 객체의 모니터에서 대기합니다. * <p> * 깨어 난 스레드는 전류 * 스레드 가이 객체의 잠금을 포기 할 때까지 진행할 수 없습니다. 깨어 난 스레드 *는이 개체의 동기화를 위해 적극적으로 경쟁 할 수있는 다른 스레드와 일반적인 방식으로 경쟁합니다. 예를 들어, * 깨어 난 스레드는이 객체를 잠그기 위해 다음 스레드라는 신뢰할 수있는 특권이나 단점이 없습니다. */ public final final void notifyall;} 이것을 알면, 우리는 미래를 스스로 구현할 아이디어가 있습니다. 스레드가 ifuture.awit과 같은 일련의 메소드를 호출하면 미래가 완료되지 않은 경우 미래에 전화하십시오. 다른 스레드가 미래를 완성 상태로 설정하면 (여기서 완성 상태에 정상 끝과 비정상적인 끝이 포함되어 있음) 미래는 대기 방법을 호출하기 때문에 대기 상태에 있던 스레드를 깨우려면 미래를 호출해야합니다. 완전한 구현은 다음과 같습니다 (코드는 이해하기 어렵지 않아야합니다. Netty의 향후 메커니즘을 참조하십시오. 관심이 있으시면 Netty의 소스 코드를 확인할 수 있습니다) :
패키지 미래; import java.util.collection; import java.util.cancellationException; import java.util.concurrent.copyonwritearraylist; import java.util.concurrent.executionException; import java.util.concurrent.timeunit; import java.util.concurrent.concurrent.concurrent.concurrent. <fre> * 정상 종료시 실행 결과가 null이 아닌 경우 결과는 실행 결과입니다. 실행 결과가 null 인 경우 result = {@link actractFuture#success_signal} * 예외가 끝나면 결과는 {@link ageholder}의 인스턴스입니다. 취소로 인해 예외가 종료되면 결과는 {@link cancellationException}의 인스턴스입니다. 그렇지 않으면 다른 예외의 인스턴스입니다 * 다음 상황은 비동기 조작이 완성 된 상태에서 완성 된 상태로 전송되게합니다. <li> 비동기 조작이 정상적으로 종료 될 때 (setSuccess 방법) </li> * <li> 비동기 조작이 비정상적으로 끝날 때 (setfailure method) </li> * </ul> * * * @author lixiaoohui * * @param <v> * asynchronous execution in asynchronous execution <vefuture <v infuture <v> 보호 된 휘발성 객체 결과; // 가시성을 보장해야합니다./ *** 리스너 세트*/ 보호 된 컬렉션 <ifuturelistener <v >> 리스너 = 새로운 사리 writearraylist <ifuturelistener <v >>; / *** 작업의 일반 실행 결과가 NULL 인 경우, 즉 클라이언트가 {@Link AbstractFuture#setSuccess (null)}을 호출 할 때* 결과를 참조하십시오. @override public boolean cance (boolean mayinterruptifrunning) {if (isdone) {// return false를 취소 할 수 없습니다. } synchronized (this) {if (iSdone) {// double check return false; } result = 새로운 원인 보유자 (새로운 취소 exception); NotifyAll; // isdone = true, 객체의 대기 대기 대기 대기 스레드에 알림} notifyListEners; // 청취자에게 비동기 조작이 완료되었음을 알리십시오. } @override public boolean iscancellable {return result == null; } @override public boolean iscancelled {return result! = null && result instanceof againholder && ((원인 홀더) 결과). } @override public boolean isdone {return result! = null; } @override public v get throws interruptedException, executionException {await; // 실행 결과를 기다릴 수 있습니다. if (원인 == null) {// 예외는 발생하지 않았으며, 비동기 작동은 일반적으로 getNow를 반환합니다. } if (CancellationException의 인스턴스 원인) {// 비동기 작동이 취소되었습니다 (CancellationException) 원인; } 새로운 executionException (원인)을 던집니다. // 기타 예외} @override public v get (긴 시간 초과, 시간 유닛 단위)가 중단 된 exception, executionException, timeoutException {if (await (timeout, unit))) {// 실행 결과를 대기 대기 대기 할 수있는 원인 = 원인; if (원인 == null) {// 예외는 발생하지 않았으며, 비동기 작동은 일반적으로 getNow를 반환합니다. } if (CancellationException의 인스턴스 원인) {// 비동기 조작이 취소되었습니다 (CancellationException) 원인; } 새 executionException (원인); // 기타 예외} // 시간이 아직 끝나지 않았으므로 시간 초과 예외를 던지면 새로운 timeoutException을 던집니다. } @override public boolean issuccess {return result == null? 거짓 :! (결과 보유자의 결과 사례); } @suppresswarnings ( "선택 취소") @override public v getnow {return (v) (result == success_signal? null : result); } @override public Throwable Cause {if (result! = null && result instance of agialholder) {return ((원인) result) .cause; } return null; } @override public ifuture <v> addListener (ifuturelistener <v> Listener) {if (Listener == null) {throw new nullpointerexception ( "Listener"); } if (isdone) {// notifyListener (리스너)를 완료 한 경우; 이것을 반환하십시오; } 동기화 된 (this) {if (! isdone) {haresers.add (리스너); 이것을 반환하십시오; }} notifyListener (리스너); 이것을 반환하십시오; } @override public ifuture <v> removelistener (ifuturelistener <v> listener) {if (larkeer == null) {throw new nullpointerexception ( "Lister"); } if (! isdone) {Listeners.remove (리스너); } 이것을 반환하십시오. } @override public ifuture <v> Await는 InterruptedException {return await0 (true); } private ifuture <v> await0 (boolean interruptable)은 인터럽트 exception {if (! isdone) {// 완료된 경우 직접 반환됩니다. // 터미널이 허용되고 중단되면 인터럽트 예외가 발생하면 (thread.crruptedexception ( " +" + " +"wrood.currentexception ( " +"writh.currentexception ( " +" 중단된."); } 부울 방해 = 거짓; 동기화 (this) {while (! isdone) {try {대기; // 잠금을 해제하고 대기 상태를 입력하고 다른 스레드가 객체의 Notify/NotifyAll Method} Catch (InterruptedException e)를 호출 할 때까지 기다립니다. } else {interrupted = true; }}}}} if (Interrupted) {// 왜 인터럽트 플래그를 여기에 설정해야합니까? 대기 방법에서 돌아온 후, 인터럽트 플래그가 지워지기 때문에 // 다른 코드가 여기에서 중단된다는 것을 알 수 있도록 여기에 재설정됩니다. Thread.CurrentThread.interrupt; }} 님이 reture; } @override public boolean await (Long TimeoutMillis)는 InterruptedException {return await0 (timeUnit.milliseconds.tonanos (timeoutMillis), true); } @override public boolean이 기다리고 있습니다 (긴 타임 아웃, TimeUnit Unit)는 InterruptedException {return await0 (unit.tonanos (timeout), true); } private boolean await0 (긴 타임 아웃 나노, 부울 인터럽트 가능)은 중단 된 예를 던져 {if (isdone) {return true; } if (timeoutNanos <= 0) {return isdone; } if (Interprupable && thread.interrupted) {Throw New InterruptedException (tostring); } long starttime = timeoutNanos <= 0? 0 : System.Nanotime; 긴 대기 시간 = TimeOutNanos; 부울 중단 = 거짓; try {synchronized (this) {if (isdone) {return true; } if (대기 시간 <= 0) {return isdone; } for (;;) {try {wait (Waittime / 10000000, (int) (Waittime % 10000000)); } catch (InterruptedException e) {if (인터럽 가능한) {Throw e; } else {interrupted = true; }} if (isdone) {return true; } else {waittime = timeoutnanos- (System.NanoTime -StartTime); if (대기 시간 <= 0) {return isdone; }}}}}} 마침내 {if (Interrupted) {thread.currentThread.interrupt; }}} @override public ifuture <v> awaituninterruptibly {retud {return await0 (false); } catch (InterruptedException e) {// 예외가 여기에 던져지면 새로운 java.lang.internalerror를 처리 할 수 없습니다. }} @override public boolean awaituninterruptibly (long timeoutmillis) {try {return await0 (timeUnit.milliseconds.toneNanos (timeoutMillis), false); } catch (InterpruptedException e) {새로운 java.lang.internalerror; }} @override public boolean awaitUninterruptibly (긴 타임 아웃, TimeUnit Unit) {try {return await0 (unit.tonanos (timeout), false); } catch (InterpruptedException e) {새로운 java.lang.internalerror; }} 보호 된 ifuture <v> setFailure (Throwable Cause) {if (setFailure0 (원인)) {notifyListEners; 이것을 반환하십시오; } New ImperalStateException을 던지십시오 ( "이미 완료 :" + this); } private boolean setfailure0 (던질 가능한 원인) {if (isdone) {return false; } 동기화 (this) {if (isdone) {return false; } 결과 = 새로운 원인 홀더 (원인); NotifyAll; } true를 반환합니다. } protected ifuture <v> setSuccess (객체 결과) {if (setSuccess0 (result)) {// notifyListEners를 성공적으로 설정 한 후; 이것을 반환하십시오; } New ImperalStateException을 던지십시오 ( "이미 완료 :" + this); } private boolean setSuccess0 (객체 결과) {if (isdone) {return false; } 동기화 (this) {if (isdone) {return false; } if (result == null) {// 비동기 작동의 정상 실행 결과는 null입니다. result = success_signal; } else {this.result = 결과; } notifyall; } true를 반환합니다. } private void notifyListEners {for (ifuturelistener <v> l : 리스너) {notifyListener (l); }} private void notifylistener (ifuturelistener <v> l) {try {l.operation completed (this); } catch (예외 E) {E.printstacktrace; }} private static class successignal {} 개인 정적 최종 클래스 원인 홀더 {최종 던지기 가능한 원인; 원인 홀더 (던질 가능한 원인) {this.cause = 원인; }}} 그래서 이것을 사용하는 방법? 위의 골격 구현을 통해 다양한 비동기 결과를 사용자 정의 할 수 있습니다. 다음은 지연된 작업입니다.
PACKED. OperationCompleted (ifuture <integer> future) 예외 {system.out.println (future.getnow)); } / *** 지연 추가* @param 지연 지연 시간 밀리 초* @param a add adding* @param b 추가* @return 비동기 결과* / public DelayadditionFuture Add (긴 지연, int a, int b) {DelayadditionFuture = 새로운 DelayAdDitionFuture; 새 스레드 (새로운 DelayadDitionTask (Delay, A, B, Future)). 시작; 미래를 반환; } 개인 클래스 DelayAdDitionTask는 실행 가능한 {개인 장거리 지연; 개인 INT A, B; 개인 DelayadditionFuture Future; Public DelayadditionTask (긴 지연, int a, int b, delayadditionfuture future) {슈퍼; this.delay = 지연; this.a = a; this.b = b; 이 .future = 미래; } @override public void run {try {thread.sleep (delay); 정수 i = a + b; // TODO는 여기에 완료 상태로 설정된 미래가 있습니다 (정상 실행 완료) 미래 .SetSuccess (i); } catch (InterpruptedException e) {// 여기에는 미래가 완료 상태로 설정되어 있습니다 (예외 완료). }}}} package future.test; import future.AbstractFuture; import future.ifuture; // 외부 공개 클래스에 두 가지 방법을 노출시킵니다. DelackFuture <integer> {@override public ifuture <integer> setsuccess (객체 결과) {return super.setsuccess (return super.setsuccess); } @override public ifuture <integer> setfailure (Throwable Cause) {return super.setfailure (원인); }} 클라이언트가 미래가 완료되는지를 적극적으로 묻지 않아도되지만 미래가 완료되면 작동 컴포형 메소드를 자동으로 호출 할 것임을 알 수 있습니다. 클라이언트는 콜백에서 논리 만 구현하면됩니다.
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.