Apa itu ExecutorService?

Sejujurnya, pertanyaan ini bukanlah hal baru. Lebih dari 13 tahun telah berlalu sejak rilis Java 5 dan paket java.util.concurrent. *, Tetapi selama sepuluh tahun saya berlatih, saya tidak pernah harus menghadapi binatang buas ini. Namun demikian, saya ditanyai pertanyaan ini beberapa kali selama wawancara dan harus berkenalan.



Tentu, hal pertama yang saya mulai adalah Habr. Tapi, sayangnya, saya hanya menemukan dua artikel di sini:



habrahabr.ru/post/260953

habrahabr.ru/post/116363



Yang pertama, tentunya, bagi mereka yang memahami dan memiliki pengalaman dengan ExecutorService. Yang kedua, sayangnya, tidak masuk ke dalam diriku. Tampaknya kecil dan "dalam kasus", tetapi setelah membaca ulang beberapa kali saya masih tidak mengerti apa itu ExecutorService dan apa yang dimakan dengannya. Jadi saya harus duduk di Eclipse, merokok, membaca javadoc dan mencari tahu.



Jadi mari kita lihat contoh sederhana:



ExecutorService service = Executors.newFixedThreadPool(3);
service.execute(new Runnable() {
    public void run() {
        System.out.println("Another thread was executed");
    }
});

      
      





Dalam contoh ini, kami membuat objek ExecutorService itu sendiri dan memanggil metode eksekusi di atasnya. Meneruskan implementasi utas paling umum ke sana. Semua ini bisa saja dibangun dengan cara kakek tua, tetapi ini, Anda lihat, jauh lebih sederhana dan lebih elegan. Faktanya, kami dengan cepat mencabangkan utas asinkron lainnya dari utas saat ini, yang dapat melakukan sesuatu di sana di latar belakang.

Kami membuat objek ExecutorService menggunakan pabrik. Metodenya cukup jelas, jadi kita tidak akan terlalu menunda-nunda. Inilah beberapa di antaranya:



ExecutorService service1 = Executors.newSingleThreadExecutor();
ExecutorService service2 = Executors.newFixedThreadPool(3);
ExecutorService service3 = Executors.newScheduledThreadPool(3);

      
      





Selain metode eksekusi, yang dipanggil dengan prinsip "api dan lupakan", layanan kami juga memiliki metode kirim. Satu-satunya perbedaan dari yang pertama adalah bahwa yang terakhir mengembalikan objek dari antarmuka Future. Ini hanyalah cara yang bagus untuk mengontrol status utas yang kami jalankan di latar belakang. Itu dilakukan seperti ini:



Future future = service.submit(new Runnable() {
    public void run() {
        System.out.println("Another thread was executed");
    }
});
...
future.get();

      
      





Perhatikan bahwa metode get akan memblokir thread saat ini dan akan menunggu hingga thread latar belakang selesai. Sekarang Anda tidak membutuhkan semua gabungan yang tidak terlihat ini! Jika kita takut thread latar belakang kita tidak akan pernah selesai, kita bisa menggunakan get (long, TimeUnit).



Terkadang Anda harus mengembalikan data dari utas latar belakang ke utas saat ini. Metode submit juga akan membantu kita dalam hal ini, tetapi sekarang kita perlu meneruskannya bukan ke Runnable, tetapi objek Callable. Faktanya, ini adalah dua antarmuka yang identik, satu-satunya perbedaan adalah yang terakhir dapat mengembalikan sesuatu:



Future future = service.submit(new Callable(){
    public Object call() throws Exception {
        System.out.println("Another thread was executed");
        return "result";
    }
});
...
System.out.println("Result: " + future.get());

      
      





Singkatnya, itu saja. Apakah metode untuk membuat ExecutorService-dan di pabrik (yang jumlahnya banyak), adalah metode ExecutorService, kesalahan penanganan masalah di thread latar belakang, tapi itu cerita lain ...



Di akhir jangan lupa untuk:



servcie.shutdown();

      
      





Atau tidak, jika semua utas latar belakang adalah daemon.



All Articles