มักจะมีงานบางอย่างในโครงการที่จำเป็นต้องดำเนินการแบบอะซิงโครนัส (ส่งไปยังพูลเธรด) เพื่อดำเนินการในขณะที่เธรดหลักมักจะต้องรู้ผลลัพธ์ของการดำเนินการแบบอะซิงโครนัส เราควรทำอย่างไรในเวลานี้? เป็นไปไม่ได้ที่จะประสบความสำเร็จด้วย Runnable เราจำเป็นต้องใช้ callable เพื่ออ่านรหัสต่อไปนี้:
นำเข้า java.util.concurrent.callable; นำเข้า java.util.concurrent.executionexception; นำเข้า java.util.concurrent.executorservice; นำเข้า java.util.concurrent.executors; Public AddTask (int a, int b) {this.a = a; this.b = b; } @Override การเรียกจำนวนเต็มสาธารณะโยนข้อยกเว้น {integer result = a + b; ผลการกลับมา; } โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่น InterruptedException, ExecutionException {ExecutorService Executor = Executors.newsingLethreathedExecutor; // JDK กลับมาแล้วและเป็นอินสแตนซ์ของอนาคต FutureTask <จำนวนเต็ม> Future = Executor.submit (ใหม่ addTask (1, 2)); ผลลัพธ์จำนวนเต็ม = future.get; // เฉพาะเมื่อสถานะของอนาคตเสร็จสมบูรณ์ (future.isdone = true) วิธีการรับจะกลับ}}} แม้ว่าเราสามารถตระหนักถึงความต้องการของการได้รับผลการดำเนินการแบบอะซิงโครนัส แต่เราพบว่าอนาคตนี้ไม่ได้มีประโยชน์จริง ๆ เพราะมันไม่ได้ให้กลไกการแจ้งเตือนซึ่งหมายความว่าเราไม่รู้ว่าอนาคตจะเสร็จสมบูรณ์เมื่อใด ดูวิธีการอินเทอร์เฟซของ java.util.concurrent.future.future:
อินเทอร์เฟซสาธารณะในอนาคต <v> {บูลีนยกเลิก (บูลีน Mayinterruptifrunning); บูลีน iscancelled; บูลีน iSdone; V ได้รับการพ่นขัดจังหวะการดำเนินการ, ExecutionException; V Get (Long Timeout, TimeUnit Unit) พ่น InterruptedException, ExecutionException, TimeOutException;} จากนี้เราจะเห็นได้ว่ากลไกในอนาคตของ JDK นั้นไม่ใช่เรื่องง่ายที่จะใช้งาน หากคุณสามารถเพิ่มผู้ฟังในอนาคตนี้และแจ้งให้ผู้ฟังทราบเมื่อเสร็จสิ้นมันจะใช้งานง่ายขึ้นเช่นเดียวกับ ifuture ต่อไปนี้:
แพ็คเกจอนาคต; นำเข้า java.util.concurrent.cancellationexception; นำเข้า java.util.concurrent.future; นำเข้า java.util.concurrent.timeUnit;/*** ผลลัพธ์ของการดำเนินการแบบอะซิงโครนัส * * @author lixiaohui * @param <v> ประเภทพารามิเตอร์ของผลการดำเนินการ */อินเทอร์เฟซสาธารณะ ifuture <v> ขยายอนาคต <v> {บูลีน issuccess; // ไม่ว่า v getNow จะประสบความสำเร็จหรือไม่ // ส่งคืนผลลัพธ์ทันที (ไม่ว่าอนาคตจะอยู่ในสถานะที่เสร็จสมบูรณ์) // เหตุผลสำหรับความล้มเหลวในการดำเนินการสามารถยกเลิกได้; // ฉันสามารถยกเลิก ifuture <v> รอการพัดผ่าน InterruptedException ได้หรือไม่ // กำลังรอบูลีนในอนาคตที่กำลังรอคอย (Long TimeOutmillis) พุ่งเข้าหาการขัดจังหวะการรับรู้; // หมดเวลารอให้บูลีนในอนาคตรอคอย (การหมดเวลานาน, เวลา Timunit TimeUnit) พ่น InterruptedException; ifuture <v> รอคอยอย่างต่อเนื่อง; // รอให้เสร็จในอนาคตไม่มีบูลีนหยุดชะงักรออย่างไม่หยุดยั้ง (Long Timeoutmillis); // หมดเวลารอให้เสร็จในอนาคตไม่มีการตอบสนองแบบขัดจังหวะบูลีนรอคอยอย่างต่อเนื่อง ifuture <v> addListener (ifutureListener <v> l); // เมื่ออนาคตเสร็จสิ้นผู้ฟังที่เพิ่มเข้ามาเหล่านี้จะได้รับแจ้ง ifuture <v> RemoveListener (ifutureListener <v> l); - ถัดไปให้ใช้ ifuture นี้กัน ก่อนหน้านี้เราจะอธิบายวิธีการที่รอวัตถุ, Object.Notifyall เนื่องจากแกนหลักดั้งเดิมของการใช้งานในอนาคตทั้งหมดเป็นวิธีการทั้งสองนี้ ดูคำอธิบายใน JDK:
วัตถุคลาสสาธารณะ { /** * ทำให้เธรดปัจจุบันรอจนกว่าเธรดอื่นจะเรียกใช้เมธอด * {@link java.lang.Object#notify} หรือวิธี * {@link java.lang.Object#notifyall} วิธีการสำหรับวัตถุนี้ * กล่าวอีกนัยหนึ่งวิธีนี้ทำงานได้อย่างตรงไปตรงมาว่ามันเพียงแค่ * ดำเนินการโทร {@code wait (0)} * หลังจากเรียกใช้วิธีนี้เธรดปัจจุบันจะปล่อยล็อคการตรวจสอบวัตถุและให้สิทธิ์การใช้งาน CPU จนกว่าจะมีการเรียกเธรดอื่นแจ้ง/ แจ้งเตือน */ โมฆะสุดท้ายสาธารณะรอพ่น InterruptedException {รอ (0); } /*** ปลุกเธรดทั้งหมดที่รออยู่บนจอภาพของวัตถุนี้ A * เธรดรออยู่บนจอภาพของวัตถุโดยเรียกใช้หนึ่งใน * @Code WAIT} วิธีการ * <p> * เธรดที่ถูกปลุกจะไม่สามารถดำเนินการต่อไปได้จนกว่าเธรด * ปัจจุบันจะยกเลิกการล็อคบนวัตถุนี้ เธรดที่ถูกปลุกขึ้นมา * จะแข่งขันในลักษณะปกติกับเธรดอื่น ๆ ที่อาจจะแข่งขันอย่างแข็งขันเพื่อซิงโครไนซ์กับวัตถุนี้ ตัวอย่างเช่น * เธรดที่ตื่นขึ้นมาไม่ได้รับสิทธิพิเศษหรือข้อเสียที่เชื่อถือได้ใน * เป็นเธรดถัดไปเพื่อล็อควัตถุนี้ */ โมฆะพื้นเมืองสุดท้ายสาธารณะ Notifyall;} หลังจากรู้เรื่องนี้เรามีความคิดที่จะนำไปใช้ในอนาคตด้วยตัวเอง เมื่อเธรดเรียกชุดของวิธีการเช่น ifuture.await หากอนาคตยังไม่เสร็จสมบูรณ์ให้โทรหาอนาคตวิธีการรอเพื่อให้เธรดป้อนสถานะการรอคอย เมื่อเธรดอื่นกำหนดอนาคตให้เป็นสถานะที่เสร็จสมบูรณ์ (โปรดทราบว่าสถานะความสำเร็จที่นี่จะรวมถึงจุดสิ้นสุดปกติและสิ้นสุดที่ผิดปกติ) วิธีการในอนาคตต้องมีการเรียกวิธีการตื่นขึ้นมาเพื่อปลุกเธรดเหล่านั้นที่อยู่ในสถานะรอเนื่องจากการเรียกใช้วิธีการรอ การใช้งานที่สมบูรณ์มีดังนี้ (รหัสไม่ควรเข้าใจยากฉันอ้างถึงกลไกในอนาคตของ NetTy หากคุณสนใจคุณสามารถตรวจสอบซอร์สโค้ดของ Netty):
แพ็คเกจอนาคต; นำเข้า java.util.Collection; นำเข้า java.util.concurrent.cancellationException; นำเข้า java.util.concurrent.copyonwritearrayList; นำเข้า java.util.concurrent.executionException; <pre> * ในตอนท้ายปกติหากผลการดำเนินการไม่เป็นโมฆะผลลัพธ์คือผลลัพธ์การดำเนินการ หากผลการดำเนินการเป็นโมฆะผลลัพธ์ = {@link AbstractFuture#success_signal} * เมื่อข้อยกเว้นสิ้นสุดผลลัพธ์จะเป็นอินสแตนซ์ของ {@link สาเหตุผู้ถือ}; หากข้อยกเว้นสิ้นสุดลงเนื่องจากการยกเลิกผลลัพธ์เป็นอินสแตนซ์ของ {@link cancellationException} มิฉะนั้นมันเป็นอินสแตนซ์ของข้อยกเว้นอื่น ๆ * สถานการณ์ต่อไปนี้จะทำให้การดำเนินการแบบอะซิงโครนัสถูกถ่ายโอนจากสถานะที่ยังไม่เสร็จ <li> เมื่อการดำเนินการแบบอะซิงโครนัสสิ้นสุดลงตามปกติ (วิธีการตั้งค่า) </li> * <li> เมื่อการดำเนินการแบบอะซิงโครนัสสิ้นสุดลงอย่างผิดปกติ (วิธีการตั้งค่า) </li> * </ul> * </pre> * @author lixiaohui * * @param <v> * ผลลัพธ์วัตถุผันผวน; // มันจะต้องรับประกันว่าจะได้รับการมองเห็น/ *** ชุดผู้ฟัง*/ คอลเลกชันที่ได้รับการป้องกัน <ifutureListener <v>> ผู้ฟัง = ใหม่ copyOnWriteArrayList <ifutureListener <V >>; / *** เมื่อผลการดำเนินการปกติของงานเป็นโมฆะนั่นคือเมื่อไคลเอ็นต์เรียก {@link AbstractFuture#setSuccess (null)},* ผลลัพธ์อ้างอิงวัตถุ*/ ส่วนตัวคงที่ SuccessSignAl Success_signal = ใหม่ SuccessSignal; @Override บูลีนสาธารณะยกเลิก (บูลีน mayInterruptifrunning) {ถ้า (isDone) {// return false ไม่สามารถยกเลิกได้; } ซิงโครไนซ์ (นี่) {ถ้า (isDone) {// ตรวจสอบซ้ำกลับเท็จ; } result = ผู้ถือสาเหตุใหม่ (การยกเลิกใหม่ใหม่); แจ้งเตือน; // isDone = จริงแจ้งเธรดที่รอการรอคอยในวัตถุ} NotifyListeners; // แจ้งให้ผู้ฟังทราบว่าการดำเนินการแบบอะซิงโครนัสเสร็จสิ้นการส่งคืนจริง } @Override บูลีนสาธารณะ iscancellable {return result == null; } @Override บูลีนสาธารณะ iscancelled {ผลการส่งคืน! = null && ผลลัพธ์อินสแตนซ์ของผู้ถือสาเหตุ && ((ผู้ถือสาเหตุ) ผลลัพธ์). เพราะอินสแตนซ์ของการยกเลิกการรับรู้; } @Override บูลีนสาธารณะ iSdone {ผลตอบแทน! = null; } @Override สาธารณะ v ได้รับการพัดผ่าน InterruptedException, ExecutionException {รอ; // รอผลการดำเนินการที่โยนได้ = สาเหตุ; ถ้า (สาเหตุ == null) {// ไม่มีข้อยกเว้นเกิดขึ้นการดำเนินการแบบอะซิงโครนัสสิ้นสุดลงตามปกติจะกลับมา getNow; } ถ้า (สาเหตุของการยกเลิกการยกเลิก) {// การดำเนินการแบบอะซิงโครนัสถูกยกเลิกการโยน (ยกเลิกการรับรู้) สาเหตุ; } โยน ExecutionException ใหม่ (สาเหตุ); // ข้อยกเว้นอื่น ๆ } @Override สาธารณะ v รับ (การหมดเวลายาว, หน่วย TimeUnit) พ่น InterruptedException, ExecutionException, TimeOutException {ถ้า (รอ (หมดเวลา, หน่วย)) {// หมดเวลารอผลการดำเนินการ ถ้า (สาเหตุ == null) {// ไม่มีข้อยกเว้นเกิดขึ้นการดำเนินการแบบอะซิงโครนัสสิ้นสุดลงตามปกติจะกลับมา getNow; } ถ้า (สาเหตุของการยกเลิกการยกเลิก) {// การดำเนินการแบบอะซิงโครนัสถูกยกเลิกการโยนโยน (ยกเลิกการรับรู้) สาเหตุ; } โยนการดำเนินการใหม่ ExecutionException (สาเหตุ); // ข้อยกเว้นอื่น ๆ } // เวลายังไม่สิ้นสุดการโยนข้อยกเว้นหมดเวลาโยน TimeException ใหม่; } @Override บูลีนสาธารณะ issuccess {return result == null? เท็จ:! (อินสแตนซ์ผลลัพธ์ของผู้ถือสาเหตุ); } @suppresswarnings ("ไม่ได้ตรวจสอบ") @Override สาธารณะ v getNow {return (v) (ผลลัพธ์ == success_signal? null: ผลลัพธ์); } @Override สาเหตุสาธารณะที่สามารถจดจำได้ {if (ผลลัพธ์! = null && ผลลัพธ์อินสแตนซ์ของผู้ถือสาเหตุ) {ผลตอบแทน ((ผู้ถือสาเหตุ) ผลลัพธ์). สาเหตุ; } return null; } @Override ifuture <v> addListener (ifutureListener <v> ผู้ฟัง) {ถ้า (ฟัง == null) {โยน nullpointerexception ใหม่ ("Listener"); } if (iSdone) {// ถ้าคุณทำ NotifyListener เสร็จสมบูรณ์ (ผู้ฟัง); คืนสิ่งนี้; } ซิงโครไนซ์ (นี่) {ถ้า (! isdone) {listeners.add (ผู้ฟัง); คืนสิ่งนี้; }} NotifyListener (ผู้ฟัง); คืนสิ่งนี้; } @Override ifuture <v> removeListener (ifutureListener <v> ผู้ฟัง) {ถ้า (ฟัง == null) {โยน nullpointerexception ใหม่ ("ผู้ฟัง"); } if (! isdone) {listeners.remove (ผู้ฟัง); } ส่งคืนสิ่งนี้; } @Override ifuture สาธารณะ <v> รอการพ่น InterruptedException {return Await0 (จริง); } ifuture ส่วนตัว <v> Await0 (บูลีนขัดจังหวะ) พ่น InterruptedException {ถ้า (! isdone) {// ถ้ามันเสร็จสิ้นมันจะถูกส่งคืนโดยตรง // หากเทอร์มินัลได้รับอนุญาตและถูกขัดจังหวะ ถูกขัดจังหวะ "); } บูลีนขัดจังหวะ = false; ซิงโครไนซ์ (นี่) {ในขณะที่ (! isdone) {ลอง {รอ; // ปล่อยล็อคและป้อนสถานะการรอรอให้เธรดอื่นเรียกใช้วิธีการแจ้งเตือน/แจ้งเตือนของวัตถุ} catch (interruptedException e) {ถ้า (ขัดจังหวะ) {โยน e; } else {interrupted = true; }}}}} ถ้า (ขัดจังหวะ) {// ทำไมเราต้องตั้งค่าสถานะอินเตอร์รัปต์ที่นี่? เพราะหลังจากกลับมาจากวิธีการรอการล้างธงจะถูกล้างออก // รีเซ็ตที่นี่เพื่อให้รหัสอื่น ๆ รู้ว่ามันถูกขัดจังหวะที่นี่ thread.currentthread.interrupt; }} ส่งคืนสิ่งนี้; } @Override Public Boolean รอคอย (Long TimeOutmillis) พ่น InterruptedException {return Await0 (TimeUnit.milliseconds.tonanos (TimeOutmillis), TRUE); } @Override บูลีนสาธารณะรออยู่ (การหมดเวลายาว, หน่วย TimeUnit) พ่น InterruptedException {return Await0 (unit.tonanos (หมดเวลา), จริง); } Boolean ส่วนตัว Await0 (Long Timeoutnanos, บูลีนขัดจังหวะ) พ่น InterruptedException {ถ้า (isdone) {return true; } if (timeoutnanos <= 0) {return iSdone; } if (interruptable && thread.interrupted) {โยน InterruptedException ใหม่ (ToString); } Long StartTime = TimeOutNanos <= 0? 0: System.Nanotime; Long Waittime = TimeOutnanos; บูลีนขัดจังหวะ = false; ลอง {ซิงโครไนซ์ (นี่) {ถ้า (isdone) {return true; } if (waittime <= 0) {return iSdone; } สำหรับ (;;) {ลอง {รอ (waittime / 1000000, (int) (waittime % 10,0000000)); } catch (interruptedException e) {ถ้า (ขัดจังหวะ) {โยน e; } else {interrupted = true; }} if (isDone) {return true; } else {waittime = timeOutnanos - (system.nanotime - starttime); if (waittime <= 0) {return iSdone; }}}}}} ในที่สุด {if (ขัดจังหวะ) {thread.currentthread.interrupt; }}} @Override ifuture สาธารณะ <v> awaituninterructably {ลอง {return await0 (เท็จ); } catch (interruptedException e) {// ถ้ามีข้อยกเว้นถูกโยนลงที่นี่มันไม่สามารถจัดการโยน java.lang.internalerror ใหม่ }} @Override บูลีนสาธารณะรอคอยอย่างต่อเนื่อง (Long TimeOutMillis) {ลอง {return Await0 (TimeUnit.milliseconds.tonanos (TimeOutMillis), FALSE); } catch (interruptedException e) {โยน java.lang.internalerror ใหม่; }} @Override บูลีนสาธารณะรอคอยอย่างต่อเนื่อง (Long Timeout, TimeUnit Unit) {ลอง {return Await0 (unit.tonanos (หมดเวลา), เท็จ); } catch (interruptedException e) {โยน java.lang.internalerror ใหม่; }} ป้องกัน ifuture <v> setFailure (สาเหตุที่โยนได้) {ถ้า (setFailure0 (สาเหตุ)) {notifyListeners; คืนสิ่งนี้; } โยน unlueLstateException ใหม่ ("เสร็จสมบูรณ์แล้ว:" + สิ่งนี้); } บูลีนส่วนตัว setFailure0 (สาเหตุที่โยนได้) {ถ้า (isdone) {return false; } ซิงโครไนซ์ (นี่) {ถ้า (isDone) {return false; } result = ผู้ถือสาเหตุใหม่ (สาเหตุ); แจ้งเตือน; } return true; } ป้องกัน ifuture <v> setSuccess (ผลลัพธ์วัตถุ) {ถ้า (setSuccess0 (ผลลัพธ์)) {// notifyListeners หลังจากตั้งค่าสำเร็จ คืนสิ่งนี้; } โยน unlueLstateException ใหม่ ("เสร็จสมบูรณ์แล้ว:" + สิ่งนี้); } บูลีนส่วนตัว setSuccess0 (ผลลัพธ์วัตถุ) {ถ้า (isDone) {return false; } ซิงโครไนซ์ (นี่) {ถ้า (isDone) {return false; } if (result == null) {// ผลลัพธ์ของการดำเนินการตามปกติของการดำเนินการแบบอะซิงโครนัสเป็นโมฆะ this.result = success_signal; } else {this.result = ผลลัพธ์; } แจ้งเตือน; } return true; } โมฆะส่วนตัว NotifyListeners {สำหรับ (ifutureListener <v> l: ผู้ฟัง) {notifyListener (l); }} โมฆะส่วนตัว NotifyListener (ifutureListener <v> l) {ลอง {l.operationcompleted (นี่); } catch (exception e) {e.printstacktrace; }} คลาสคงที่ระดับความสำเร็จในระดับส่วนตัว {} คลาสสุดท้ายคงที่ระดับสุดท้ายผู้ถือสาเหตุ {สาเหตุที่โยนได้สุดท้าย; ผู้ถือสาเหตุ (สาเหตุที่โยนได้) {this.cuse = สาเหตุ; - ดังนั้นจะใช้สิ่งนี้ได้อย่างไร? ด้วยการใช้งานโครงกระดูกข้างต้นเราสามารถปรับแต่งผลลัพธ์แบบอะซิงโครนัสต่างๆ ต่อไปนี้เป็นงานล่าช้า:
Package Future.test; นำเข้า future.ifuture; นำเข้า future.ifutureListener;/** * การเพิ่มความล่าช้า * @author lixiaohui * */คลาสสาธารณะ delayadder {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {ใหม่ delayadder.add (3 * 1000, 1, 2) Operationcompleted (ifuture <teger> อนาคต) โยนข้อยกเว้น {system.out.println (future.getNow); } / *** การเพิ่มความล่าช้า* @param การหน่วงเวลาล่าช้าระยะเวลามิลลิวินาที* @param การเพิ่ม* @param b เพิ่มเติม* @return asynchronous ผลลัพธ์* / public delayadditionFuture เพิ่ม (ล่าช้านาน, int a, int b) เธรดใหม่ (ใหม่ DelayAdditionTask (Delay, A, B, Future)) เริ่มต้น; กลับมาอนาคต } คลาสส่วนตัว DelayAdditionTask ใช้งาน Runnable {ความล่าช้าส่วนตัวยาว; ส่วนตัว int a, b; Private DelayAdditionFuture Future; Public DelayAdditionTask (ล่าช้านาน, int a, int b, delayAdditionFuture อนาคต) {super; this.delay = ล่าช้า; this.a = a; this.b = b; this.future = อนาคต; } @Override โมฆะสาธารณะเรียกใช้ {ลอง {thread.sleep (ล่าช้า); จำนวนเต็ม i = a + b; // สิ่งที่ต้องทำที่นี่คืออนาคตที่กำหนดเป็นสถานะความสำเร็จ (การดำเนินการปกติเสร็จสมบูรณ์) อนาคต Setsuccess (i); } catch (interruptedException e) {// todo นี่คือการตั้งค่าในอนาคตเป็นสถานะความสมบูรณ์ (ข้อยกเว้นเสร็จสมบูรณ์) future.SetFailure (e.getCause); }}}} แพ็คเกจ future.test; นำเข้า future.abstractfuture; นำเข้า future.ifuture; // เพียงแค่เปิดเผยสองวิธีไปยังระดับสาธารณะ delayadditionFuture ขยายบทคัดย่อ future <integer> {@Override ifuture } @Override ifuture สาธารณะ <Integer> setFailure (สาเหตุที่โยนได้) {return super.setFailure (สาเหตุ); - คุณจะเห็นว่าลูกค้าไม่จำเป็นต้องถามอย่างแข็งขันว่าอนาคตจะเสร็จสมบูรณ์หรือไม่ แต่จะโทรกลับวิธีการดำเนินงานโดยอัตโนมัติเมื่ออนาคตเสร็จสมบูรณ์ ลูกค้าต้องการใช้ตรรกะในการโทรกลับเท่านั้น
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น