Kita semua tahu bahwa sebelum JDK1.5, ketika konkurensi bisnis diterapkan di Java, pemrogram biasanya perlu menyelesaikan implementasi kode secara mandiri. Tentu saja, ada beberapa kerangka kerja sumber terbuka yang menyediakan fungsi-fungsi ini, tetapi fungsi-fungsi ini masih kurang berguna sebagai fungsi yang disertakan dengan JDK. Saat merancang program simultan multi-utas Java berkualitas tinggi, untuk mencegah fenomena seperti lompatan mati, seperti wait(), notify(), dan sinkronisasi sebelum menggunakan Java, sering kali perlu mempertimbangkan kinerja, kebuntuan, keadilan, dan sumber daya. Banyak faktor seperti manajemen dan cara menghindari bahaya yang disebabkan oleh keamanan thread sering kali mengadopsi beberapa strategi keamanan yang lebih kompleks, yang meningkatkan beban pengembangan programmer. Untungnya, setelah munculnya JDK1.5, Sun Master (Doug Lea) akhirnya memperkenalkan toolkit java.util.concurrent untuk menyederhanakan penyelesaian bersamaan bagi kami, programmer kecil yang malang. Pengembang dapat menggunakan ini untuk secara efektif mengurangi kondisi balapan dan rangkaian kebuntuan. Paket konkuren memecahkan masalah ini dengan sangat baik dan memberi kita model program konkuren yang lebih praktis.
Pelaksana: Pelaksana tugas Runnable tertentu.
ExecutorService: Manajer kumpulan thread, ada banyak kelas implementasi, saya akan memperkenalkan beberapa di antaranya. Kami dapat mengirimkan Runnable dan Callable ke pool untuk penjadwalan.
Semaphore: semafor penghitungan
ReentrantLock: Kunci reentrant yang saling eksklusif, fungsinya serupa dengan yang disinkronkan, tetapi jauh lebih kuat.
Masa Depan: Ini adalah antarmuka untuk berinteraksi dengan Runnable dan Callable, seperti mendapatkan hasil yang dikembalikan setelah eksekusi thread, dll. Ini juga menyediakan pembatalan untuk mengakhiri thread.
BlockingQueue: memblokir antrian.
CompletionService: Ekstensi ExecutorService, yang dapat memperoleh hasil eksekusi thread
CountDownLatch: Kelas pembantu sinkronisasi yang memungkinkan satu atau lebih thread menunggu hingga serangkaian operasi yang dilakukan di thread lain selesai.
CyclicBarrier: kelas pembantu sinkronisasi yang memungkinkan sekelompok thread menunggu satu sama lain hingga titik penghalang umum tercapai
Masa Depan: Masa Depan mewakili hasil perhitungan asinkron.
ScheduledExecutorService: ExecutorService yang menjadwalkan perintah untuk dijalankan setelah penundaan tertentu atau secara berkala.
Selanjutnya kami akan memperkenalkannya satu per satu
Deskripsi metode utama pelaksana
newFixedThreadPool (kumpulan thread ukuran tetap)
Buat kumpulan thread yang dapat menggunakan kembali rangkaian thread tetap dan menjalankan thread ini dalam antrean bersama yang tidak dibatasi (hanya yang diminta yang akan menunggu dalam antrean untuk dieksekusi). Jika ada thread yang terhenti karena kegagalan selama eksekusi sebelum dimatikan, thread baru akan melakukan tugas berikutnya di tempatnya (jika diperlukan).
newCachedThreadPool (kumpulan thread tanpa batas, dapat melakukan daur ulang thread otomatis)
Membuat kumpulan thread yang membuat thread baru sesuai kebutuhan, tetapi menggunakan kembali thread yang dibuat sebelumnya saat tersedia. Untuk program yang melakukan banyak tugas asinkron berumur pendek, kumpulan thread ini sering kali meningkatkan kinerja program. Memanggil eksekusi akan menggunakan kembali thread yang dibuat sebelumnya (jika thread tersedia). Jika tidak ada thread yang tersedia, thread baru akan dibuat dan ditambahkan ke kumpulan. Hentikan dan hapus dari cache thread-thread yang tidak digunakan selama 60 detik. Oleh karena itu, kumpulan thread yang tidak digunakan dalam waktu lama tidak akan menggunakan sumber daya apa pun. Perhatikan bahwa Anda dapat menggunakan konstruktor ThreadPoolExecutor untuk membuat kumpulan thread dengan properti serupa tetapi detail berbeda (seperti parameter batas waktu).
newSingleThreadExecutor (utas latar belakang tunggal)
Buat Executor yang menggunakan satu thread pekerja dan menjalankan thread dalam antrean tak terbatas. (Perhatikan bahwa jika thread tunggal ini dihentikan karena kegagalan selama eksekusi sebelum dimatikan, thread baru akan melakukan tugas berikutnya di tempatnya, jika diperlukan). Tugas dijamin dijalankan secara berurutan, dan tidak lebih dari satu thread yang akan aktif pada waktu tertentu. Berbeda dengan newFixedThreadPool(1) yang setara, eksekutor yang dikembalikan dengan metode ini dijamin dapat menggunakan thread lain tanpa mengkonfigurasi ulang.
Metode ini mengembalikan objek ExecutorService, yang dapat dipahami sebagai kumpulan thread.
Fungsi thread pool ini relatif lengkap. Anda dapat mengirimkan tugas dengan submit() dan mengakhiri kumpulan thread dengan shutdown().
import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class MyExecutor extends Thread {private int index;public MyExecutor(int i){ this.index=i;}public void run(){ coba{ System.out.println("["+ini.index+"] mulai...."); Thread.sleep((int)(Matematika.random()*)); System.out.println("["+ini.index+"] end."); } catch(Pengecualian e){ e.printStackTrace(); }}public static void main(String args[]){ ExecutorService service=Executors.newFixedThreadPool(); for(int i=;i<;i++){ service.execute(new MyExecutor(i)); //service.submit(new MyExecutor(i)); } System.out.println("kirim selesai");
Meskipun beberapa informasi dicetak, tidak begitu jelas cara kerja kumpulan thread ini. Mari tingkatkan waktu tidur sebanyak 10 kali lipat.
Thread.sleep((int)(Matematika.acak()*10000));
Melihat lebih jauh, Anda akan melihat dengan jelas bahwa hanya 4 thread yang dapat dieksekusi. Ketika sebuah thread dieksekusi, thread baru akan dieksekusi. Artinya, setelah kita mengirimkan semua thread, kumpulan thread akan menunggu hingga penutupan terakhir dieksekusi. Kami juga akan menemukan bahwa thread yang mengirimkan ditempatkan dalam "antrean tidak terbatas". Ini adalah antrian terurut (BlockingQueue, yang akan dibahas di bawah).
Selain itu, ia menggunakan fungsi statis dari Executors untuk menghasilkan kumpulan thread tetap. Seperti namanya, thread di kumpulan thread tidak akan dilepaskan, meskipun dalam keadaan Idle.
Hal ini akan menyebabkan masalah kinerja. Misalnya, jika ukuran kumpulan thread adalah 200, ketika semua thread digunakan, semua thread akan tetap berada di pool, dan memori serta pergantian thread yang sesuai (sementara(benar)+sleep loop). ) akan meningkat.
Jika Anda ingin menghindari masalah ini, Anda harus menggunakan ThreadPoolExecutor() secara langsung untuk membuatnya. Anda dapat mengatur "jumlah maksimum thread", "jumlah minimum thread" dan "waktu idle thread keepAlive" seperti kumpulan thread pada umumnya.
Ini adalah penggunaan dasar kumpulan thread.
Tiang sinyal
Semafor penghitungan. Secara konseptual, semaphore memelihara kumpulan izin. Jika perlu, setiap acquire() diblokir hingga izin tersedia, lalu izin diperoleh. Setiap rilis() menambahkan izin, yang berpotensi melepaskan pengakuisisi pemblokiran. Namun, alih-alih menggunakan objek lisensi sebenarnya, Semaphore hanya menghitung jumlah lisensi yang tersedia dan mengambil tindakan yang sesuai.
Semaphore sering digunakan untuk membatasi jumlah thread yang dapat mengakses sumber daya tertentu (fisik atau logis). Misalnya, kelas berikut menggunakan semafor untuk mengontrol akses ke kumpulan konten:
Ini adalah situasi nyata. Setiap orang mengantri untuk pergi ke toilet. Hanya ada dua tempat di toilet. Ketika 10 orang datang, mereka harus mengantri.
import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;public class MySemaphore extends Thread {Semaphore position;private int id;public MySemaphore(int i,Semaphore s){ this.id=i; this.position=s;}jalankan kekosongan publik(){ coba{ if(position.availablePermits()>){ System.out.println("Pelanggan["+ini.id+"] masuk toilet, ada ruang"); } else{ System.out.println("Pelanggan["+ this.id+"] masuk toilet, tidak ada spasi, antrian"); } position.acquire(); System.out.println("Pelanggan ["+this.id+"] memperoleh kursi pit"); Thread.sleep((int)(Math.random()*)); System.out.println("Pelanggan ["+this.id+"] telah selesai menggunakan"); ) { e.printStackTrace(); }} public static void main(String args[]){ ExecutorService list=Executors.newCachedThreadPool(); Semaphore(); for(int i=;i<;i++){ list.submit(new MySemaphore(i+,position)); } list.shutdown(); Selesai, perlu dibersihkan"); position.release();}}
Kunci Masuk Kembali
Kunci mutex yang masuk kembali yang memiliki beberapa perilaku dasar dan semantik yang sama dengan kunci monitor implisit yang diakses menggunakan metode dan pernyataan yang disinkronkan, namun lebih kuat.
ReentrantLock akan dimiliki oleh thread yang baru saja berhasil memperoleh kunci dan belum melepaskan kunci tersebut. Ketika kunci tersebut tidak dimiliki oleh thread lain, kunci pemanggil thread akan berhasil memperoleh kunci tersebut dan kembali. Jika thread saat ini sudah memegang kunci, metode ini akan segera kembali. Anda dapat menggunakan metode isHeldByCurrentThread() dan getHoldCount() untuk memeriksa apakah hal ini terjadi.
Konstruktor kelas ini menerima parameter keadilan opsional.
Jika disetel ke true, di bawah pertentangan dari beberapa thread, kunci ini cenderung memberikan akses ke thread yang telah menunggu paling lama. Jika tidak, kunci ini tidak akan menjamin perintah akses tertentu.
Dibandingkan dengan pengaturan default (menggunakan penguncian yang tidak adil), program yang menggunakan penguncian yang adil akan memiliki throughput keseluruhan yang sangat rendah (yaitu, akan sangat lambat, seringkali sangat lambat) ketika diakses oleh banyak thread, namun akan memiliki kinerja yang buruk dalam memperoleh kunci dan jaminan alokasi kunci Perbedaannya kecil dalam hal keseimbangan.
Namun, perlu dicatat bahwa penguncian yang adil tidak menjamin keadilan penjadwalan thread. Oleh karena itu, salah satu dari banyak thread yang menggunakan kunci adil mungkin memiliki banyak peluang untuk berhasil, yang terjadi ketika thread aktif lainnya tidak diproses dan saat ini tidak menahan kunci tersebut.
Perhatikan juga bahwa metode tryLock tanpa batas waktu tidak menggunakan pengaturan keadilan. Karena cara ini bisa berhasil selama kuncinya tersedia meskipun thread lain sudah menunggu.
Dianjurkan untuk selalu berlatih segera dan menggunakan blok try untuk memanggil kunci. Dalam konstruksi sebelum/sesudah, kode yang paling umum adalah sebagai berikut:
class X { private final ReentrantLock lock = new ReentrantLock(); // ... public void m() { lock.lock(); membuka kunci() } }}
Contoh saya:
import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.locks.ReentrantLock;kelas publik MyReentrantLock extends Thread{TestReentrantLock lock;private int id;public MyReentrantLock(int i,TestReentrantLock test ){ this.id=i; this.lock=test;}jalankan kekosongan publik(){ lock.print(id);}public static void main(String args[]){ ExecutorService service=Executors.newCachedThreadPool(); TestReentrantLock lock=new TestReentrantLock(); kirim(baru MyReentrantLock(i,lock)); } service.shutdown();}}kelas TestReentrantLock{private ReentrantLock lock=new ReentrantLock(); public void print(int str){ coba{ lock.lock(); System.out.println(str+"get"); )); } catch(Pengecualian e){ e.printStackTrace(); } akhirnya{ System.out.println(str+"release");
Memblokir Antrian
Antrean yang mendukung dua operasi tambahan: menunggu antrian menjadi tidak kosong saat mengambil elemen, dan menunggu ruang tersedia saat menyimpan elemen.
BlockingQueue tidak menerima elemen nol. Beberapa implementasi menampilkan NullPointerException saat mencoba menambahkan, meletakkan, atau menawarkan elemen null. null digunakan sebagai nilai peringatan untuk menunjukkan bahwa operasi polling gagal.
BlockingQueue dapat dibatasi kapasitasnya. Ia dapat memiliki sisa Kapasitas pada waktu tertentu, di luar itu ia tidak dapat menempatkan elemen tambahan tanpa pemblokiran.
BlockingQueue tanpa batasan kapasitas internal selalu melaporkan Integer.MAX_VALUE kapasitas yang tersisa.
Implementasi BlockingQueue terutama digunakan untuk antrean produsen-konsumen, namun juga mendukung antarmuka Koleksi. Jadi, misalnya, dimungkinkan untuk menghapus elemen sembarang dari antrian menggunakan hapus(x).
Namun, operasi ini biasanya tidak dilakukan secara efisien dan hanya dapat digunakan sesekali dan secara terencana, misalnya saat melakukan dequeue pesan.
Implementasi BlockingQueue aman untuk thread. Semua metode antrian dapat menggunakan penguncian internal atau bentuk kontrol konkurensi lainnya untuk mencapai tujuannya secara otomatis.
Namun, sejumlah besar operasi Pengumpulan (tambahkanSemua, berisiSemua, simpanSemua, dan hapusSemua) tidak selalu dilakukan secara otomatis kecuali dinyatakan secara spesifik dalam implementasi.
Jadi, misalnya, addAll(c) mungkin gagal (melemparkan pengecualian) setelah menambahkan hanya beberapa elemen di c.
BlockingQueue pada dasarnya tidak mendukung operasi "close" atau "shutdown" apa pun untuk menunjukkan bahwa tidak ada lagi item yang akan ditambahkan.
Kebutuhan dan penggunaan fungsi ini cenderung bergantung pada implementasi. Misalnya, strategi yang umum adalah memasukkan objek end-of-stream atau racun khusus ke dalam produsen dan menafsirkannya berdasarkan kapan konsumen mendapatkannya.
Contoh berikut menunjukkan fungsionalitas dasar antrian pemblokiran ini.
import java.util.concurrent.BlockingQueue;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.LinkedBlockingQueue;public class MyBlockingQueue extends Thread {public static BlockingQueue<String> queue = LinkedBlockingQueue<String>();pribadi int indeks;publik MyBlockingQueue(int i) { this.index = i;} public void run() { coba { antrian.put(String.valueOf(this.index)); System.out.println("{" + this.index + " } dalam antrian!"); } catch (Pengecualian e) { e.printStackTrace(); }} public static void main(String args[]) { ExecutorService service = Executors.newCachedThreadPool(); for (int i = ; i < ; i++) { service.submit(new MyBlockingQueue(i) } Thread thread = new Thread() { public void run() { coba { while (benar) { Thread.sleep((int) (Matematika.acak() * )); if(MyBlockingQueue.queue.isEmpty()) istirahat; MyBlockingQueue.queue.take(); System.out.println(str + " telah mengambil!"); } } catch (Pengecualian e) { e.printStackTrace(); penutupan();}}
--------------------------Hasil eksekusi-----------------
{0} dalam antrean!
{1} dalam antrian!
{2} dalam antrian!
{3} dalam antrian!
0 telah diambil!
{4} dalam antrian!
1 telah diambil!
{6} dalam antrian!
2 telah diambil!
{7} dalam antrian!
3 telah diambil!
{8} dalam antrian!
4 telah diambil!
{5} dalam antrian!
6 telah diambil!
{9} dalam antrian!
7 telah diambil!
8 telah diambil!
5 telah diambil!
9 telah diambil!
----------------------------------------
Layanan Penyelesaian
Sebuah layanan yang memisahkan pembuatan tugas asinkron baru dari penggunaan hasil tugas yang telah diselesaikan. Produser menyerahkan tugas yang harus dilakukan. Pengguna mengambil tugas yang telah selesai dan memproses hasilnya sesuai urutan penyelesaiannya. Misalnya, CompletionService dapat digunakan untuk mengelola IO asinkron. Tugas melakukan operasi baca dikirimkan sebagai bagian dari program atau sistem. Kemudian, ketika operasi baca selesai, operasi lain dilakukan di bagian program yang berbeda , mungkin dalam urutan operasi yang diminta. Urutannya berbeda.
Biasanya, CompletionService bergantung pada Executor terpisah untuk benar-benar melakukan tugas, dalam hal ini CompletionService hanya mengelola antrean penyelesaian internal. Kelas ExecutorCompletionService menyediakan implementasi metode ini.
import java.util.concurrent.Callable;import java.util.concurrent.CompletionService;import java.util.concurrent.ExecutorCompletionService;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors; kelas publik MyCompletionService mengimplementasikan Callable <String> {id int pribadi; Layanan Penyelesaian Saya publik (int i){ this.id=i;}public static void main(String[] args) melempar Pengecualian{ ExecutorService service=Executors.newCachedThreadPool(); CompletionService<String> penyelesaian=new ExecutorCompletionService<String>(service); i<;i++){ penyelesaian.kirim(Layanan Penyelesaian Saya baru(i) } for(int i=;i<;i++){ System.out.println(completion.take().get()); } service.shutdown();} public String call() melempar Pengecualian { Integer time=(int)(Math.random()*); System.out.println(this.id+" start"); Thread.sleep(waktu); System.out.println(this.id+" end"); } catch(Pengecualian e){ e.printStackTrace(); } kembalikan ini.id+":"+waktu;}}
Hitung MundurLatch
Kelas pembantu sinkronisasi yang memungkinkan satu atau lebih thread menunggu hingga serangkaian operasi yang dilakukan di thread lain selesai.
Inisialisasi CountDownLatch dengan hitungan yang diberikan. Karena metode countDown() dipanggil, metode menunggu akan diblokir hingga hitungan saat ini mencapai nol.
Setelah itu, semua thread yang menunggu dilepaskan dan semua panggilan berikutnya untuk menunggu kembali dengan segera. Perilaku ini hanya terjadi sekali - penghitungan tidak dapat diatur ulang. Jika Anda perlu mengatur ulang hitungan, pertimbangkan untuk menggunakan CyclicBarrier.
CountDownLatch adalah alat sinkronisasi umum yang memiliki banyak kegunaan. Gunakan CountDownLatch yang diinisialisasi dengan hitungan 1 sebagai kait hidup/mati sederhana, atau entri: semua thread yang memanggil menunggu menunggu di entri hingga entri dibuka oleh thread yang memanggil countDown().
CountDownLatch yang diinisialisasi dengan N dapat menyebabkan thread menunggu hingga N thread menyelesaikan operasi, atau menunggu hingga operasi menyelesaikan N kali.
Fitur yang berguna dari CountDownLatch adalah bahwa ia tidak memerlukan thread yang memanggil metode countDown untuk menunggu hingga hitungan mencapai nol sebelum melanjutkan, melainkan mencegah thread apa pun untuk melanjutkan melalui menunggu hingga semua thread dapat lewat.
Contoh di bawah ini ditulis oleh orang lain dan sangat jelas.
import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class TestCountDownLatch {public static void main(String[] args) throws InterruptedException { // Memulai kunci hitung mundur final CountDownLatch mulai = new CountDownLatch(); // Akhir dari kunci hitung mundur final CountDownLatch end = baru CountDownLatch(); // Sepuluh kontestan final ExecutorService exec = Executors.newFixedThreadPool(); for (int indeks = ; indeks < ; indeks++) { final int NO = indeks + ; { coba { mulai.menunggu();//selalu memblokir Thread.sleep((long) (Math.random() * )); System.out.println("Tidak." + TIDAK + "tiba"); } catch (InterruptedException e) {} akhirnya { end.countDown(); println("Permainan Dimulai"); mulai.countDown(); akhir.menunggu(); Sistem.keluar.println("Permainan Berakhir");
Metode CountDownLatch yang paling penting adalah countDown() dan waiting(). Metode pertama biasanya menghitung mundur satu kali, dan metode kedua menunggu hitungan mundur ke 0. Jika tidak mencapai 0, metode tersebut hanya akan memblokir dan menunggu.
Penghalang Siklik
Kelas pembantu sinkronisasi yang memungkinkan sekelompok thread menunggu satu sama lain hingga titik penghalang umum tercapai.
CyclicBarrier berguna dalam program yang melibatkan sekumpulan thread berukuran tetap yang harus menunggu satu sama lain dari waktu ke waktu. Karena penghalang dapat digunakan kembali setelah benang tunggu dilepaskan, maka disebut penghalang siklik.
CyclicBarrier mendukung perintah Runnable opsional yang dijalankan hanya sekali pada setiap titik penghalang, setelah thread terakhir dalam serangkaian thread telah tiba (tetapi sebelum semua thread dilepaskan). Operasi penghalang ini berguna saat memperbarui status bersama sebelum melanjutkan semua thread yang berpartisipasi.
Contoh penggunaan: Berikut ini adalah contoh penggunaan penghalang dalam desain dekomposisi paralel, contoh grup wisata yang sangat klasik:
impor java.text.SimpleDateFormat;impor java.util.Date;impor java.util.concurrent.BrokenBarrierException;impor java.util.concurrent.CyclicBarrier;impor java.util.concurrent.ExecutorService;impor java.util.concurrent.Executors; public class TestCyclicBarrier {// Waktu yang dibutuhkan untuk mendaki: Shenzhen, Guangzhou, Shaoguan, Changsha, Private static int[] timeWalk = { , , , , , }; // Tur mengemudi mandiri private static int[] timeSelf = { , , , , }; , , } ; String statis sekarang() { SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); sdf.format(tanggal baru()) + ": "; } Tur kelas statis mengimplementasikan Runnable { private int[] kali; penghalang CyclicBarrier pribadi; private String tourName; this.times = kali; this.tourName = tourName; this.barrier = penghalang; } public void run() { coba { Thread.sleep(times[] * ); System.out.println(sekarang() + tourName + " Mencapai Shenzhen"); Thread.sleep(times[] * ); System.out.println(now() + tourName + " Mencapai Guangzhou" ); penghalang.menunggu(); Thread.sleep(kali[] * ); System.out.println(sekarang() + tourName + " Mencapai Shaoguan"); penghalang.menunggu(); Thread.sleep(kali[] * ); Sistem.keluar.println(sekarang() + tourName + " Mencapai Changsha"); penghalang.menunggu(); System.out.println(sekarang() + tourName + " Mencapai Wuhan penghalang.await(); } catch (InterruptedException e) {} catch (BrokenBarrierException e) { } } } public static void main(String[] args) {// Tiga grup tur CyclicBarrier Barrier = new CyclicBarrier(); "WalkTour", timeWalk)); exec.submit(Tur baru(penghalang, "SelfTour", timeSelf));//Ketika kami mengomentari kode berikut, kami akan menemukan bahwa program tersebut diblokir dan tidak dapat terus berjalan. exec.submit(Tur baru(penghalang, "BusTour", timeBus)); exec.shutdown();
Atribut terpenting dari CyclicBarrier adalah jumlah peserta, dan metode terpenting adalah menunggu(). Ketika semua thread telah memanggil menunggu(), itu berarti thread ini dapat terus dieksekusi, jika tidak maka thread tersebut akan menunggu.
Masa depan
Masa depan mewakili hasil perhitungan asinkron. Ini menyediakan metode untuk memeriksa apakah penghitungan telah selesai, menunggu hingga penghitungan selesai, dan mengambil hasil penghitungan.
Setelah penghitungan selesai, hanya metode get yang dapat digunakan untuk mengambil hasilnya. Jika perlu, metode ini dapat diblokir sebelum penghitungan selesai. Pembatalan dilakukan dengan metode batal.
Metode tambahan disediakan untuk menentukan apakah tugas diselesaikan secara normal atau dibatalkan. Setelah penghitungan selesai, penghitungan tidak dapat dibatalkan.
Jika Anda menggunakan Future untuk pembatalan tetapi tidak memberikan hasil yang dapat digunakan, Anda dapat mendeklarasikan tipe formal Future<?> dan mengembalikan null sebagai hasil dari tugas yang mendasarinya.
Kita telah melihat ini di CompletionService sebelumnya, fungsi dari Masa Depan ini, dan ini dapat ditentukan sebagai objek pengembalian saat mengirimkan thread.
Layanan Pelaksana Terjadwal
ExecutorService yang menjadwalkan perintah untuk dijalankan setelah penundaan tertentu atau secara berkala.
Metode jadwal membuat tugas dengan berbagai penundaan dan mengembalikan objek tugas yang dapat digunakan untuk membatalkan atau memeriksa eksekusi. Metode scheduleAtFixedRate dan scheduleWithFixedDelay membuat dan menjalankan tugas tertentu yang berjalan secara berkala hingga dibatalkan.
Perintah yang dikirimkan menggunakan Executor.execute(java.lang.Runnable) dan metode pengiriman ExecutorService dijadwalkan dengan penundaan yang diminta sebesar 0.
Penundaan nol dan negatif (tetapi bukan titik) diperbolehkan dalam metode jadwal, dan ini dianggap sebagai permintaan yang harus segera dieksekusi.
Semua metode jadwal menerima penundaan dan periode relatif sebagai parameter, bukan waktu atau tanggal absolut. Sangat mudah untuk mengubah waktu absolut yang diwakili oleh Tanggal ke dalam bentuk yang diperlukan.
Misalnya, untuk menjadwalkan proses di kemudian hari, gunakan: schedule(task, date.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS).
Namun perlu diperhatikan bahwa karena protokol sinkronisasi waktu jaringan, penyimpangan jam, atau faktor lainnya, tanggal kedaluwarsa yang relatif tertunda tidak harus sesuai dengan tanggal saat ini dari tugas yang diaktifkan.
Kelas Executors menyediakan metode pabrik yang praktis untuk implementasi ScheduledExecutorService yang disediakan dalam paket ini.
Contoh berikut juga populer di Internet.
import static java.util.concurrent.TimeUnit.SECONDS;import java.util.Date;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.ScheduledFuture;public class TestScheduledThread { public static void main(String[] args) { final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(); beeper Runnable akhir = Runnable baru() { int count = ; public void run() { System.out.println(Tanggal baru() + " bip " + (++hitungan)); // Jalankan setelah detik dan setiap detik terakhir ScheduledFuture beeperHandle = scheduler.scheduleAtFixedRate(beeper, , , SECONDS); // Jalankan setelah beberapa detik, dan tunggu beberapa detik setelah tugas terakhir selesai dijalankan, lalu jalankan kembali setiap kali final ScheduledFuture beeperHandle = scheduler.scheduleWithFixedDelay(beeper, , , SECONDS); jadwal(runnable baru() { public void run() { beeperHandle.cancel(benar); beeperHandle.cancel(benar); penjadwal.shutdown();
Demikianlah kami telah merangkum fungsi-fungsi yang lebih penting dari paket konkuren, semoga dapat membantu pemahaman kita.