Mengapa menggunakan ExecutorService untuk utas yang sudah berjalan lama?

8

Saya ingin objek yang akan menelurkan daemon thread yang akan terus berjalan selama proses berlangsung. Katakanlah, hanya demi argumen, bahwa ini adalah utas dalam sistem tertanam, dan menunggu untuk menerima dan menangani perintah pada beberapa port diagnostik. Tapi, bisa jadi apa saja kok. Gagasan utamanya adalah menonton sesuatu selama jangka waktu yang lama; Itu tidak melakukan urutan tugas .

Kebijaksanaan umum Jawa mengatakan, Jangan pernah instantiate Thread, Gunakan sebagai ExecutorServicegantinya. (Misalnya, lihat jawaban ini ) Tapi apa untungnya? Menggunakan benang kolam renang sebagai sarana untuk membuat thread lama berjalan tunggal tampaknya sia-sia. Bagaimana itu akan lebih baik daripada jika saya menulis ini?

class Foobar {
    public Foobar() {
        this.threadFactory = Executors.defaultThreadFactory();
        ...
    }

    public Foobar(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
        ...
    }

    public void start() {
        fooThread = threadFactory.newThread(new Runnable() { ... });
        fooThread.setDaemon(true);
        fooThread.start();
    }
    ...
}

Catatan: pertanyaan ini tampaknya mirip dengan pertanyaan saya, tetapi jawabannya hanya mengatakan bagaimana cara menggunakan kumpulan utas, bukan mengapa .

Solomon Lambat
sumber
Tidak yakin tentang Java, tetapi bahasa lain biasanya secara eksplisit merekomendasikan menghindari kumpulan utas untuk utas yang berjalan lama. Seperti yang Anda katakan, tidak masuk akal untuk menggunakan salah satu dari sumber daya yang terbatas untuk jangka waktu yang lama.
Frank Hileman

Jawaban:

11

Saya pikir "Tidak pernah" adalah kata yang terlalu kuat. Ini lebih seperti aturan optimasi kedua: "Jangan (belum)".

Menurut pendapat saya, alasan utama untuk menggunakan layanan pelaksana adalah untuk mengelola jumlah utas yang berjalan. Jika Anda mengizinkan kelas sewenang-wenang untuk membuat utas mereka sendiri, Anda dapat dengan cepat menemukan diri Anda dengan 1.000 utas yang terikat CPU (atau terus-menerus bertukar konteks). Layanan pelaksana menyelesaikan masalah itu, dengan memberikan batasan pada pembuatan utas.

Alasan kedua adalah bahwa memulai sebuah utas dengan benar membutuhkan pemikiran:

  • Daemon atau non-daemon? Kesalahan ini dan Anda perlu menelepon System.exit()untuk mematikan program Anda.
  • Prioritas apa? Banyak programmer Swing mengira mereka pintar dengan memutar utas latar belakang untuk menangani tugas-tugas yang intensif CPU, tetapi tidak menyadari bahwa utas pengiriman acara berjalan dengan prioritas tertinggi dan utas anak mewarisi prioritas orangtua mereka.
  • Bagaimana cara menangani pengecualian yang tidak tertangkap?
  • Apa nama yang tepat? Tampaknya konyol untuk terobsesi dengan nama, tetapi utas yang diberi nama tujuan memberi Anda banyak bantuan dalam debugging.

Yang mengatakan, ada kasus-kasus tertentu di mana itu layak untuk memutar benang daripada mengandalkan kolam benang.

  • Saya akan menggunakan kumpulan utas dalam kasus di mana aplikasi saya menghasilkan tugas dan saya ingin mengontrol bagaimana tugas-tugas itu dijalankan.
  • Saya akan membuat utas khusus di mana satu atau beberapa utas didedikasikan untuk memproses acara yang dihasilkan secara eksternal .

"Dibangkitkan secara eksternal" bergantung pada konteks. Kasing klasik adalah utas di akhir antrian atau soket pesan, yang perlu menyurvei antrian itu dan melakukan beberapa tindakan (yang mungkin melibatkan pengiriman tugas ke kumpulan).

Namun, itu juga bisa merujuk pada peristiwa yang dihasilkan di luar modul tertentu: misalnya, saya menganggap sangat masuk akal bahwa Log4J AsyncAppendermemutar utas sendiri daripada mengharapkan aplikasi untuk menyediakan kumpulan.

kdgregory
sumber