غالبًا ما تكون هناك بعض المهام في المشروع التي يجب تنفيذها بشكل غير متزامن (تم تقديمها إلى تجمع الخيوط) ليتم تنفيذها ، في حين أن الخيط الرئيسي يحتاج غالبًا إلى معرفة نتائج التنفيذ غير المتزامن. ماذا يجب أن نفعل في هذا الوقت؟ من المستحيل تحقيقه باستخدام Runnable ، نحتاج إلى استخدام القابل للاتصال لقراءة الكود التالي:
استيراد java.util.concurrent.callable ؛ استيراد java.util.concurrent.executionException ؛ استيراد java.util.concurrent.executorservice ؛ استيراد java.util.concurrent.executors ؛ استيراد java.util.concurrent.future ؛ AddTask العامة (int a ، int b) {this.a = a ؛ this.b = b ؛ } Override Public Integer Call Riseves {Integer result = a + b ؛ نتيجة العودة } إلقاء الفراغ الثابتة العامة (سلسلة [] args) interruptedException ، ExecutionException {executorService executor = Executors.NewSingLethReadExecutor ؛ // عاد JDK حتى الآن وهي مثيلات من مستقبل FutureTask <integer> المستقبل = Executor.Submit (AddTask جديد (1 ، 2)) ؛ نتيجة عدد صحيح = المستقبل على الرغم من أننا يمكن أن ندرك متطلبات الحصول على نتائج التنفيذ غير المتزامنة ، فقد وجدنا أن هذا المستقبل ليس مفيدًا في الواقع لأنه لا يوفر آلية إخطار ، مما يعني أننا لا نعرف متى سيتم إكمال المستقبل (إذا احتجنا إلى استطلاع ISDONE () للحكم ، فهذا يبدو أنه لا توجد حاجة لاستخدام هذا). ألقِ نظرة على طريقة واجهة java.util.concurrent.future.future:
الواجهة العامة في المستقبل <V> {Boolean Cancel (Boolean Mayinterrupruptifrunning) ؛ منطقية iscancelled. منطقية Isdone. V GET RISOWS InterruptedException ، ExecutionException ؛ V GET (ant timeout ، timeunit und) رميات interruptedException ، ExecutionException ، timeoutexception ؛} من هذا يمكننا أن نرى أن الآلية المستقبلية لـ JDK ليست سهلة الاستخدام. إذا تمكنت من إضافة مستمع إلى هذا المستقبل والسماح له بإخطار المستمع عند اكتماله ، فسيكون ذلك أسهل في الاستخدام ، تمامًا مثل Ifuture التالي:
Package Future ؛ Import java.util.concurrent.cancellationException ؛ import java.util.concurrent.future ؛ استيراد java.util.concurrent.timeunit ؛/*** نتيجة عملية غير متزامنة. * * author lixiaohui * param <v> اكتب معلمة نتيجة التنفيذ */الواجهة العامة ifuture <v> يمتد مستقبل <v> {boolean issuccess ؛ // ما إذا كان V GetNow ناجحًا ؛ // إرجاع النتيجة على الفور (بغض النظر عما إذا كان المستقبل في الحالة المكتملة) قابلة للارتفاع ؛ // سبب فشل التنفيذ يمكن إلحاقه ؛ // هل يمكنني إلغاء ifuture <v> في انتظار رميات InterruptedException ؛ . . ifuture <v> awaituninterruptlured. // في انتظار الانتهاء من المستقبل ، لا يوجد انقطاع منطقي في انتظار (timeoutmillis الطويل) ؛ // timeout ينتظر الانتهاء في المستقبل ، لا استجابة مقاطعة منطقية في انتظار (antimout timeout ، timeunit timeunit) ؛ ifuture <v> addListener (ifutureListener <V> l) ؛ // عند اكتمال المستقبل ، سيتم إخطار هؤلاء المستمعين المضافة ifuture <v> removelistener (ifutureListener <V> l) ؛ } بعد ذلك ، دعنا ننفذ هذا ifuture معًا. قبل ذلك ، سنشرح طريقة الكائن ألق نظرة على التفسير في JDK:
يتسبب كائن الفئة العامة { /** * في انتظار مؤشر الترابط الحالي حتى يستدعي مؤشر ترابط آخر * {link java.lang.object#notify} أو طريقة * {link java.lang.object#eletifyall} لهذا الكائن. * وبعبارة أخرى ، تتصرف هذه الطريقة تمامًا كما لو أنها ببساطة * تنفذ المكالمة {code wait (0)}. * بعد استدعاء هذه الطريقة ، سيصدر مؤشر الترابط الحالي قفل شاشة الكائن والتخلي عن حقوق استخدام وحدة المعالجة المركزية. إلى أن يقوم مؤشر ترابط آخر بإخطار/ إخطار */ رميات الانتظار الفريدة النهائية العامة المقطع {انتظر (0) ؛ } /*** يستيقظ جميع مؤشرات الترابط التي تنتظر شاشة هذا الكائن. ينتظر مؤشر ترابط A * على شاشة الكائن عن طريق استدعاء إحدى طرق * {Code Wait}. * <p> * لن تتمكن الخيوط المسكون من المتابعة حتى يتخلى مؤشر ترابط * الحالي * القفل على هذا الكائن. سوف تتنافس المواضيع المسكون * بالطريقة المعتادة مع أي مؤشرات ترابط أخرى قد تتنافس بنشاط على مزامنة هذا الكائن ؛ على سبيل المثال ، * لا تتمتع المواضيع المسكونة بأي امتياز أو عيب موثوق به في * كونه الخيط التالي لقفل هذا الكائن. */ public final native void notifyall ؛} بعد معرفة ذلك ، لدينا فكرة لتنفيذ المستقبل بأنفسنا. عندما يستدعي مؤشر الترابط سلسلة من الأساليب مثل ifuture.await ، إذا لم يتم إكمال المستقبل ، فاستدعاء طريقة المستقبل. عندما تضع مؤشرات ترابط أخرى في المستقبل على حالة الانتهاء (لاحظ أن حالة الإنجاز هنا تتضمن الطرف الطبيعي والنهاية غير الطبيعية) ، يجب استدعاء طريقة notifyall لإيقاظ تلك الخيوط التي كانت في حالة الانتظار بسبب استدعاء طريقة الانتظار. التنفيذ الكامل هو كما يلي (لا ينبغي فهم الرمز. أشير إلى الآلية المستقبلية لـ NetTy. إذا كنت مهتمًا ، فيمكنك التحقق من رمز NetTy المصدر):
حزمة المستقبل ؛ استيراد java.util.collection ؛ استيراد java.util.concurrent.cancellationException ؛ استيراد java.util.concurrent.copyonwritearraylist ؛ import java.util.concurrent.executionexception ؛ <pre> * في النهاية العادية ، إذا لم تكن نتيجة التنفيذ خالية ، فإن النتيجة هي نتيجة التنفيذ ؛ إذا كانت نتيجة التنفيذ خالية ، فإن النتيجة = {Link AbstractFuture#Success_Signal} * عندما ينتهي الاستثناء ، تكون النتيجة مثيلًا لـ {link causeholder} ؛ إذا انتهى الاستثناء بسبب الإلغاء ، فإن النتيجة هي مثيل لـ {link cancellationException} ، وإلا فإنه مثيل للاستثناءات الأخرى * ستتسبب المواقف التالية <li> عندما تنتهي العملية غير المتزامنة بشكل طبيعي (طريقة setSuccess) </li> * <li> عندما تنتهي العملية غير المتزامنة بشكل غير متزامن (طريقة setFaileure) </li> * </ul> * </pre> * * * author lixiaohui * * param <v> * من النما نتيجة الكائن المتقلبة ؛ // يجب أن تكون مضمونة لتكون رؤية/ *** مجموعة مستمع*/ مجموعة محمية <ifutureListener <V>> المستمعين = جديد CopyOnWriteArrayList <ifutureListener <v>> ؛ / *** عندما تكون نتيجة التنفيذ العادية للمهمة خالية ، أي عندما يستدعي العميل {Link AbstractFuture#setSuccess (NULL)} ،* تشير النتائج إلى الكائن*/ خاص النجاحات النهائية الثابتة = نجاح جديد ؛ Override Public Boolean Cancel (Boolean Mayinterrupruprunning) {if (Isdone) {// return false لا يمكن إلغاء ؛ } synchronized (هذا) {if (ISDONE) {// check double check return false ؛ } النتيجة = حامل السبب الجديد (cancellationException جديد) ؛ إخطار // isDone = true ، قم بإبلاغ مؤشر الترابط في انتظار الانتظار على الكائن} // إخطار المستمع بأن العملية غير المتزامنة قد اكتملت عودة حقيقية ؛ } Override public boolean iscancellable {return return == null ؛ } Override public boolean iscancelled {return return! = null && result extleof causeholder && ((causeholder) نتيجة). } Override public boolean isDone {return return! = null ؛ } Override Public V Get RiswsptedException ، ExecutionException {Await ؛ // انتظر نتيجة التنفيذ سبب رمي = السبب ؛ إذا كان (السبب == null) {// لم يحدث استثناء ، انتهت العملية غير المتزامنة عادةً getNow ؛ } if (cause extryof cancellationException) {// تم إلغاء العملية غير المتزامنة رمي (cancellationException) ؛ } رمي التنفيذ الجديد (السبب) ؛ // استثناءات أخرى} Override public v get (ant timeout ، timeUnit unit) يلقي InterruptedException ، ExecutionException ، timeoutexception {if (earait (timeout ، unit)) {// timeout في انتظار أن يكون السبب الذي يطرحه التنفيذ قد يكون ذلك = السبب ؛ إذا كان (السبب == null) {// لم يحدث استثناء ، انتهت العملية غير المتزامنة عادةً getNow ؛ } إذا تم إلغاء (cause easueof cancellationException) {// تم إلغاء العملية غير المتزامنة رمي رمي (cancellationException). } رمي التنفيذ الجديد (السبب) ؛ // استثناءات أخرى} // لم ينتهي الوقت بعد ، مع إلقاء استثناء مهلة على إلقاء TimeOutException ؛ } Override public boolean issuccess {return return == null؟ خطأ:! (مثيل النتيجة من حامل السبب) ؛ } suppressWarnings ("Unchecked") Override public v getNow {return (v) (result == success_signal؟ null: result) ؛ } Override public throw cause {if (result! = null && result extleof causeholder) {return (((dainholder). } إرجاع فارغ ؛ } Override public ifuture <v> addListener (ifutureListener <V> مستمع) {if (leader == null) {رمي nullpointerxception ("المستمع") ؛ } if (ISDONE) {// إذا كنت قد أكملت إعلام stiMiLListener (مستمع) ؛ إرجاع هذا ؛ } synchronized (هذا) {if (! isDone) {beaders.add (المستمع) ؛ إرجاع هذا ؛ }) إرجاع هذا ؛ } Override public ifuture <v> removelistener (IfuTuRelistener <V> beasher) {if (leader == null) {رمي nullpointerxception ("المستمع") ؛ } if (! isDone) {leaders.remove (مستمع) ؛ } إرجاع هذا ؛ } Override public ifuture <v> انتظر رميات interruptedException {return await0 (true) ؛ } ifuture private <v> await0 (المقاطعة المنطقية) رميات interruptedException {if (! isDone) {// إذا تم الانتهاء منها ، فسيتم إرجاعه مباشرة // إذا تم السماح بالمحطة ومقاطعتها ، فسيتم إلقاء استثناء من المقاطعة إذا كان (interruptled && interruptred) توقف. ") ؛ } مقاطعة منطقية = خطأ ؛ Synchronized (هذا) {بينما (! iSdone) {try {wait ؛ // حرر القفل وأدخل حالة الانتظار ، انتظر مؤشرات الترابط الأخرى للاتصال بأسلوب الإخطار/إخطار الكائن} catch (interruptedException e) {if (interruptable) {throw e ؛ } else {interrupted = true ؛ }}}}} إذا (مقاطع) {// لماذا نحتاج إلى تعيين علامة المقاطعة هنا؟ لأنه بعد العودة من طريقة الانتظار ، يتم مسح علامة المقاطعة ، // إعادة تعيين هنا بحيث تعرف الرموز الأخرى أنها متقطع هنا. thread.currentThread.Interrupt ؛ }} إرجاع هذا ؛ } Override Public Boolean في انتظار (timeoutmillis longout) interruptedException {return await0 (timeUnit.milliseconds.tonanos (timeoutmillis) ، true) ؛ } Override Public Boolean في انتظار (ant timeout ، وحدة TimeUnit) يلقي InterruptedException {return await0 (unit.tonanos (timeout) ، true) ؛ } BOOLEAN الخاص AWAIT0 (TimeOutnanos الطويل ، المقاطعة المنطقية) يلقي InterruptedException {if (iSdone) {return true ؛ } if (timeOutnanos <= 0) {return Isdone ؛ } if (interruptable && thread.interreded) {رمي جديد interruptedException (toString) ؛ } وقت بدء طويل = timeOtnanos <= 0؟ 0: System.Nanotime ؛ وقت الانتظار طويل = timeOtnanos ؛ المنقطع المنطقي = خطأ ؛ حاول {Synchronized (هذا) {if (IsDone) {return true ؛ } if (waittime <= 0) {return isDone ؛ } لـ (؛؛) {try {wait (waittime / 1000000 ، (int) (waittime ٪ 1000000)) ؛ } catch (interruptedException e) {if (interruptable) {throw e ؛ } else {interrupted = true ؛ }} if (iSdone) {return true ؛ } آخر {waittime = timeOutnanos - (system.nanotime - startTime) ؛ if (waittime <= 0) {return isDone ؛ }}}}}} أخيرًا {if (مقاطع) {thread.currentThread.interrupt ؛ }}} Override public ifuture <V> AwaitUnInterRuptively {try {return await0 (false) ؛ } catch (interruptedException e) {// إذا تم إلقاء استثناء هنا ، فلا يمكن معالجته رميًا جديدًا java.lang.internalerror ؛ }} Override Public Boolean Awaituninterruptlruptive (timeoutmillis) {try {return await0 (timeUnit.milliseconds.tonanos (timeOutMillis) ، false) ؛ } catch (interruptedException e) {throw new java.lang.internalerror ؛ }} Override Public Boolean AwaitUninterruptluredruptlruptive (ant timeout ، وحدة الوقت) {try {return await0 (unit.tonanos (timeout) ، false) ؛ } catch (interruptedException e) {throw new java.lang.internalerror ؛ }} محمية ifuture <v> setFailure (سبب قابلين عن رمي) {if (setFailure0 (cause)) {stifyListeners ؛ إرجاع هذا ؛ } رمي جديد غير alustalstateException ("أكمل بالفعل:" + هذا) ؛ } private boolean setFailure0 (سبب قابلية للتسمية) {if (isDone) {return false ؛ } synchronized (هذا) {if (iSdone) {return false ؛ } النتيجة = حامل السبب الجديد (السبب) ؛ إخطار } إعادة صواب ؛ } ifuture المحمي <V> setSuccess (نتيجة الكائن) {if (setSuccess0 (result)) {// etrifylisteners بعد الإعداد بنجاح ؛ إرجاع هذا ؛ } رمي جديد غير alustalstateException ("أكمل بالفعل:" + هذا) ؛ } setSuccess0 (نتيجة الكائن) {if (iSdone) {return false ؛ } synchronized (هذا) {if (iSdone) {return false ؛ } if (result == null) {// نتيجة التنفيذ الطبيعي للعملية غير المتزامنة هي null this.result = success_signal ؛ } آخر {this.result = result ؛ } إخطار ؛ } إعادة صواب ؛ } private void notifyListeners {for (ifuTuRelistener <V> l: bearners) {etrifyListener (l) ؛ }} private void notifyListener (ifutureListener <V> l) {try {l.operationCompleted (this) ؛ } catch (استثناء e) {E.PrintStackTrace ؛ }} Success Successsignal {} الفئة النهائية الثابتة الخاصة {قضية رمي نهائية ؛ causeholder (السبب القابل للتسمية) {this.cause = cause ؛ }}} إذن كيف تستخدم هذا؟ مع تطبيق الهيكل العظمي أعلاه ، يمكننا تخصيص نتائج غير متزامنة مختلفة. فيما يلي مهمة تأخر:
package future.test ؛ reput future. OperationCompleted (ifuture <integer> المستقبل) يلقي الاستثناء {system.out.println (Future.getNow) ؛ } / *** تأخير إضافة* param تأخير التأخير المدة milliseconds* param إضافة* param b إضافة* return return* / public delayadditionfuture add (تأخير طويل ، int a ، int b) {delayadditionfuture future = new delayadditionfuture ؛ موضوع جديد (تأخير جديد ديداسك (تأخير ، أ ، ب ، المستقبل)). ابدأ ؛ العودة في المستقبل } private class delayadditiontask تنفذ {private long delay ؛ Private int a ، b ؛ التأخير الخاص مستقبل ؛ Public AdventDditionTask (تأخير طويل ، int a ، int b ، develyadditionfuture future) {super ؛ this.delay = التأخير ؛ this.a = a ؛ this.b = b ؛ this.future = المستقبل ؛ } Override public void Run {try {thread.sleep (delay) ؛ عدد صحيح i = a + b ؛ // TODO هنا هو المستقبلي الذي تم تعيينه إلى حالة الإنجاز (يتم الانتهاء من التنفيذ العادي) في المستقبل. } catch (interruptedException e) {// todo هنا هو المستقبلي إلى حالة الانتهاء (تم الانتهاء من الاستثناء) future.setFailure (e.getCause) ؛ }}}} package future.test ؛ استيراد Future.abstractFuture ؛ استيراد المستقبل. } Override public ifuture <integer> setFailure (السبب القابل للتسمية) {return super.setFailure (cause) ؛ }} يمكنك أن ترى أن العميل لا يحتاج إلى أن يسأل بنشاط ما إذا كان المستقبل قد اكتمل ، ولكنه سيعاد تلقائيًا إلى طريقة التشغيل OperationCompleted عند اكتمال المستقبل. يحتاج العميل فقط إلى تنفيذ المنطق في رد الاتصال.
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.