Seringkali ada beberapa tugas dalam proyek yang perlu dieksekusi secara tidak sinkron (diserahkan ke kumpulan utas) untuk dieksekusi, sementara utas utama sering perlu mengetahui hasil eksekusi asinkron. Apa yang harus kita lakukan saat ini? Tidak mungkin dicapai dengan Runnable, kita perlu menggunakan Callable untuk membaca kode berikut:
impor java.util.concurrent.callable; impor java.util.concurrent.executionException; impor java.util.concurrent.executorservice; impor java.util.concurrent. addTask publik (int a, int b) {this.a = a; this.b = b; } @Override Public Integer Call melempar Exception {integer hasil = a + b; hasil pengembalian; } public static void main (String [] args) melempar InterruptedException, ExecutionException {ExecutorService Executor = Executors.NewsingletHreadExecutor; // JDK telah kembali sejauh ini dan merupakan contoh Futuretask Future <Integer> Future = Executor.submit (AddTask baru (1, 2)); Integer Hasil = Future.get; // Hanya Saat Status Masa Depan selesai (Found.isdone = true), metode GET akan kembali}} Meskipun kami dapat menyadari persyaratan untuk mendapatkan hasil eksekusi yang tidak sinkron, kami menemukan bahwa masa depan ini sebenarnya tidak berguna karena tidak memberikan mekanisme pemberitahuan, yang berarti kami tidak tahu kapan masa depan akan selesai (jika kami perlu polling isdone () untuk menilai, rasanya tidak perlu menggunakan ini). Lihatlah metode antarmuka java.util.concurrent.future.future:
antarmuka publik masa depan <v> {boolean cancel (boolean mayintruppifrunning); Boolean terkutuk; Boolean Isdone; V dapatkan lemparan interruptedException, ExecutionException; V dapatkan (waktu lama, unit timeUnit) melempar interruptedException, ExecutionException, timeoutexception;} Dari sini kita dapat melihat bahwa mekanisme JDK di masa depan sebenarnya tidak mudah digunakan. Jika Anda dapat menambahkan pendengar ke masa depan ini dan membiarkannya memberi tahu pendengar ketika selesai, akan lebih mudah digunakan, seperti halnya IFURTURE berikut:
Paket Masa Depan; Impor Java.util.concurrent.CancellationException; impor java.util.concurrent.future; import java.util.concurrent.timeunit;/*** Hasil dari operasi yang asinkron. * * @author lixiaohui * @param <v> Jenis parameter hasil eksekusi */antarmuka publik IfUture <V> Memperluas Future <V> {Boolean Issuccess; // Apakah V Getnow berhasil; // mengembalikan hasilnya segera (terlepas dari apakah masa depan berada di negara bagian yang sudah selesai) Penyebab yang dapat dilempar; // Alasan kegagalan eksekusi dapat dibatalkan; // Dapatkah saya membatalkan IFUTURE <V> menunggu melempar interruptedException; // menunggu penyelesaian masa depan boolean menunggu (waktu lama noutmillis) melempar interruptedException; // Timeout Tunggu untuk penyelesaian masa depan Boolean menunggu (waktu lama, timeunit timeunit) melempar interruptedException; Ifuture <v> menunggu diinteruprik; // Menunggu penyelesaian di masa depan, tidak ada gangguan Boolean yang menunggu dengan mudah (waktu lama); // Batas waktu menunggu penyelesaian di masa depan, tidak ada respons interupsi Boolean menunggu (waktu lama, waktu waktu waktu); Ifuture <v> addListener (ifutureListener <v> l); // Ketika masa depan selesai, pendengar yang ditambahkan ini akan diberitahu IFUTURE <V> Removelistener (IfutureListener <V> l); } Selanjutnya, mari kita terapkan Ifuture ini bersama -sama. Sebelum ini, kami akan menjelaskan metode Object.Wait, Object.NotifyAll, karena inti asli dari seluruh implementasi masa depan adalah dua metode ini. Lihatlah penjelasan di JDK:
Objek kelas publik { /** * menyebabkan utas saat ini menunggu sampai utas lain memunculkan metode * {@link java.lang.Object#notify} atau metode * {@link java.lang.object#notifyall} untuk objek ini. * Dengan kata lain, metode ini berperilaku persis seolah -olah itu hanya * melakukan panggilan {@code tunggu (0)}. * Setelah memanggil metode ini, utas saat ini akan melepaskan kunci monitor objek dan menyerahkan hak penggunaan CPU. Sampai utas lain memanggil Notify/ NotifyAll */ Public Final Void Wait Throws InterruptedException {tunggu (0); } /*** Bangun semua utas yang menunggu monitor objek ini. A * Thread menunggu pada monitor objek dengan memanggil salah satu metode * {@code tunggu}. * <p> * Benang yang dibangunkan tidak akan dapat melanjutkan sampai saat ini * utas melepaskan kunci pada objek ini. Benang yang dibangunkan * akan bersaing dengan cara biasa dengan utas lain yang mungkin * secara aktif bersaing untuk menyinkronkan pada objek ini; Misalnya, * utas yang dibangunkan tidak menikmati hak istimewa atau kerugian yang dapat diandalkan dalam * menjadi utas berikutnya yang mengunci objek ini. */ public final void notifyall;} Setelah mengetahui hal ini, kami memiliki ide untuk mengimplementasikan masa depan sendiri. Ketika utas memanggil serangkaian metode seperti IFUTURE.AWAIT, jika masa depan belum selesai, maka hubungi Future.Wait Metode untuk membuat utas memasuki keadaan menunggu. Ketika utas lain menetapkan masa depan ke status penyelesaian (perhatikan bahwa status penyelesaian di sini termasuk akhir normal dan akhir abnormal), masa depan. Metode yang tidak ada perlu dipanggil untuk membangunkan utas yang dalam keadaan menunggu karena memanggil metode tunggu. Implementasi lengkapnya adalah sebagai berikut (kode tidak boleh sulit dipahami. Saya merujuk pada mekanisme Netty di masa depan. Jika Anda tertarik, Anda dapat memeriksa kode sumber Netty):
Paket Masa Depan; Impor Java.util.Collection; impor java.util.concurrent.cancellationException; impor java.util.concurrent.copyonwriteArraylist; impor java.util.concurrent.executionException; impor java.util.concurrent.TimeRent.time; java.util.concurrent.TimeOutException;/** * <pe> * Pada ujung normal, jika hasil eksekusi tidak nol, maka hasilnya adalah hasil eksekusi; Jika hasil eksekusi adalah null, maka hasil = {@link abstractFuture#success_signal} * Ketika pengecualian berakhir, hasilnya adalah instance dari {@link causholder}; Jika pengecualian berakhir karena pembatalan, hasilnya adalah contoh dari {@link CancellationException}, jika tidak, itu adalah contoh dari pengecualian lainnya * Situasi berikut akan menyebabkan operasi asinkron yang ditransfer dari keadaan yang belum selesai, (yaitu, BIBUNGAN, BIBUK PERTANYAAN PERTANYAAN PERTANYAAN PERTANYAAN PERTANYAAN PERTANYAAN PERTANYAAN PERTANYAAN PERNAH PERNAH PERNAH PERNAH PERNAH PERNAH DITERIMA. <li> Ketika operasi asinkron berakhir secara normal (metode setSuccess) </li> * <li> Ketika operasi asinkron berakhir secara abnormal (metode setFailure) </li> * </ul> * </sekutif @Author lixiaohui * * @param <v> * jenis asinyous {volume {volume {volume {volseR {volseR <param <param> hasil objek yang mudah menguap; // perlu dijamin visibilitas/ *** set pendengar*/ koleksi terlindungi <ifutureListener <v>> listeners = new copyonWriteArrayList <ifutureListener <v>>; / *** Ketika hasil eksekusi normal dari tugas adalah nol, yaitu, ketika klien memanggil {@link abstractFuture#setSuccess (null)},* hasil merujuk objek*/ private static final successSignal success_signal = new SuccessSignal; @Override public boolean cancel (boolean mayinterruptunning) {if (isDone) {// return false tidak dapat dibatalkan; } disinkronkan (this) {if (isDone) {// periksa ganda return false; } result = new Causholder (New CancellationException); Notifyall; // isDone = true, beri tahu utas menunggu pada menunggu objek} notifylisteners; // Beri tahu pendengar bahwa operasi asinkron telah selesai kembali benar; } @Override public boolean isCancellable {return hasil == null; } @Override public boolean isCancelled {return hasil! = Null && hasil instance dari causholder && ((causholder) hasil) .Cause instance dari CancellationException; } @Override public boolean isDone {return hasil! = Null; } @Override public v Dapatkan lemparan interruptedException, ExecutionException {menunggu; // tunggu hasil eksekusi yang dapat dilempar = penyebab; if (cause == null) {// tidak ada pengecualian terjadi, operasi asinkron berakhir biasanya kembali getnow; } if (Cause Instanceof CancellationException) {// Operasi asinkron dibatalkan lemparan (CancellationException) Penyebab; } lempar ExecutionException baru (penyebab); // Pengecualian Lain} @Override Public v Get (Timeout Long, TimeUnit Unit) Melempar InterruptedException, ExecutionException, TimeOutException {if (menunggu (timeout, unit)) {// Timeout menunggu hasil eksekusi yang dapat dilempar Penyebab = penyebab; if (cause == null) {// tidak ada pengecualian terjadi, operasi asinkron berakhir biasanya kembali getnow; } if (Cause Instanceof CancellationException) {// Operasi asinkron dibatalkan lemparan lemparan (CancellationException) Penyebab; } lempar eksekusi baru (penyebab); // pengecualian lainnya} // Waktu belum berakhir, melempar pengecualian timeout lempar timeoutexception baru; } @Override public boolean issuccess {return result == null? false:! (Hasil instance dari pemegang sebab); } @SuppressWarnings ("Uncecked") @Override public v getnow {return (v) (result == success_signal? Null: hasil); } @Override Publicable Penyebab {if (hasil! = Null && hasil instance dari causeHolder) {return ((CauseHolder) hasil) .cause; } return null; } @Override public ifuture <v> addListener (ifutureListener <v> pendengar) {if (listener == null) {lempar nullpointerException baru ("pendengar"); } if (isDone) {// Jika Anda telah menyelesaikan NotifyListener (pendengar); kembalikan ini; } disinkronkan (this) {if (! isDone) {listeners.add (pendengar); kembalikan ini; }} notifyListener (pendengar); kembalikan ini; } @Override public ifuture <V> Removelistener (IfutureListener <V> pendengar) {if (listener == null) {lempar nullpointerException baru ("pendengar"); } if (! isDone) {listeners.remove (pendengar); } kembalikan ini; } @Override public ifuture <V> menunggu lemparan interruptedException {return wait0 (true); } private ifuture <v> menunggu (boolean interruptable) melempar interruptedException {if (! isDone) {// Jika telah selesai, itu akan dikembalikan secara langsung // jika terminal diizinkan dan terganggu, interupsi akan dilemparkan (interruptable && thread. terputus. "); } boolean interrupted = false; disinkronkan (this) {while (! isDone) {coba {tunggu; // Lepaskan kunci dan masukkan status tunggu, tunggu utas lain untuk memanggil metode notify/notifyall objek} catch (interruptedException e) {if (interruptable) {throw e; } else {interrupted = true; }}}}} if (interrupted) {// Mengapa kita perlu mengatur bendera interupsi di sini? Karena setelah kembali dari metode tunggu, bendera interupsi dihapus, // setel ulang di sini sehingga kode lain tahu bahwa itu terganggu di sini. Thread.currentthread.interrupt; }} kembalikan ini; } @Override Public Boolean menunggu (waktu lama Millis) melempar InterruptedException {return wait0 (timeunit.milliseconds.tonanos (timeoutmillis), true); } @Override public boolean menunggu (waktu lama, unit timeunit) melempar interruptedException {return wait0 (unit.tonanos (timeout), true); } private boolean wait0 (long timeoutnanos, boolean interruptable) melempar 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; WaitTime Long = Timeoutnanos; Boolean terputus = false; coba {disinkronkan (this) {if (isDone) {return true; } if (WaitTime <= 0) {return isDone; } untuk (;;) {coba {tunggu (WaitTime / 1000000, (int) (WaitTime % 1000000)); } catch (InterruptedException e) {if (interruptable) {throw e; } else {interrupted = true; }} if (isDone) {return true; } else {waittime = timeoutnanos - (System.nanoTime - startTime); if (WaitTime <= 0) {return isDone; }}}}}} akhirnya {if (interrupted) {thread.currentThread.interrupt; }}} @Override public ifuture <v> AwaitUninterruptibly {coba {return wait0 (false); } catch (InterruptedException e) {// Jika pengecualian dilemparkan ke sini, itu tidak dapat ditangani melempar java.lang.internalerror baru; }} @Override Public Boolean AwaitUninterricture (Long TimeoutMillis) {coba {return wait0 (timeunit.milliseconds.tonanos (timeoutmillis), false); } catch (InterruptedException e) {lempar java.lang.internalError baru; }} @Override Public Boolean AwaitUninterricture (Timeout Long, TimeUnit Unit) {coba {return wait0 (unit.tonanos (timeout), false); } catch (InterruptedException e) {lempar java.lang.internalError baru; }} terlindungi ifuture <v> setFailure (penyebab yang dapat dilempar) {if (setFailure0 (penyebab)) {notifyListeners; kembalikan ini; } lempar IllegalStateException baru ("sudah lengkap:" + ini); } private boolean setFailure0 (penyebab lempar) {if (isDone) {return false; } disinkronkan (this) {if (isDone) {return false; } result = new causholder (penyebab); Notifyall; } return true; } terlindungi ifuture <v> setSucCess (hasil objek) {if (setSucCess0 (hasil)) {// notifylisteners setelah pengaturan berhasil; kembalikan ini; } lempar IllegalStateException baru ("sudah lengkap:" + ini); } private boolean setsuccess0 (hasil objek) {if (isDone) {return false; } disinkronkan (this) {if (isDone) {return false; } if (result == null) {// hasil eksekusi normal operasi asinkron adalah null this.result = success_signal; } else {this.result = hasil; } notifyall; } return true; } private void notifyListeners {for (ifutureListener <v> l: listeners) {notifyListener (l); }} private void notifyListener (ifutureListener <v> l) {coba {l.OperationCompleted (this); } catch (Exception e) {E.PrintStackTrace; }} private static class successSignal {} private static class causholder {final throwable cause; CauseHolder (Throwable Cause) {this.Cause = Cause; }}} Jadi bagaimana cara menggunakan ini? Dengan implementasi kerangka di atas, kami dapat menyesuaikan berbagai hasil asinkron. Berikut ini adalah tugas yang tertunda:
Paket Future.test; Impor Future.ifuture; Impor Future.ifutureListener;/** * Penambahan penundaan * @author lixiaohui * */Delayadder kelas publik {public static Main (String [] args) {new Delayadder.Add (3 * 1000, 1, 2) .addlistener (new ifutureler. OperationCompleted (IFUTURE <Integer> Future) melempar Exception {System.out.println (Future.getNow); } / *** Penambahan penundaan* @param Delay Delasi durasi milidonds* @param a Tambahan* @param B Penambahan* @return asynchronous hasil* / penundaan publicadditionfuture add (penundaan panjang, int a, int b) {delayadditionFuture future = new DelayadditionFuture; utas baru (DelayadditionTask baru (Delay, A, B, Future)). Mulai; kembali masa depan; } private class delayadditionTask mengimplementasikan runnable {private long delay; Private int a, b; masa depan delayditionfuture pribadi; DelayadditionTask publik (lama penundaan, int a, int b, delayadditionfuture future) {super; this.delay = tunda; this.a = a; this.b = b; this.future = masa depan; } @Override public void run {try {thread.sleep (tunda); Integer I = A + B; // Todo di sini adalah yang akan datang ke Status Penyelesaian (eksekusi normal selesai) Future.setsuccess (i); } catch (InterruptedException e) {// TODO Di sini adalah yang akan datang ke Status Penyelesaian (pengecualian selesai) Future.setFailure (e.getCause); }}}} Paket Future.test; Impor Future.AbstractFuture; Impor Future.ifuture; // Cukup ungkapkan dua metode ke kelas publik luar DelayadditionFuture Extends AbstractFuture <Integer> {@Override ifuture public <Integer> setSuccess (hasil objek) {super.setsetsets public <Integer> (hasil Objek) {super.setsetscess <Integer> } @Override public ifuture <Integer> setFailure (penyebab lempar) {return super.setFailure (penyebab); }} Anda dapat melihat bahwa klien tidak perlu secara aktif bertanya apakah masa depan selesai, tetapi secara otomatis akan memanggil kembali metode OperationCompleted ketika masa depan selesai. Klien hanya perlu mengimplementasikan logika di panggilan balik.
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.