Java Timer vs ExecutorService?

263

Saya memiliki kode tempat saya menjadwalkan tugas menggunakan java.util.Timer. Saya melihat sekeliling dan melihat ExecutorServicedapat melakukan hal yang sama. Jadi pertanyaan ini di sini, sudahkah Anda menggunakan Timerdan ExecutorServiceuntuk menjadwalkan tugas, apa manfaat dari satu menggunakan lebih dari yang lain?

Juga ingin memeriksa apakah ada yang menggunakan Timerkelas dan mengalami masalah yang ExecutorServicediselesaikan untuk mereka.

kal
sumber
1
Dan jika Anda membutuhkan sesuatu yang lebih fitur, periksa kuarsa . Ini memberi Anda lebih banyak kontrol pekerjaan, termasuk penjadwalan cron seperti, penjadwalan sadar-cluster, kontrol individual atas pekerjaan (konsep-konsep seperti satu berjalan pada satu waktu, dependensi, dll). --Tim
Tim

Jawaban:

313

Menurut Java Concurrency in Practice :

  • Timerbisa peka terhadap perubahan jam sistem, ScheduledThreadPoolExecutorbukan.
  • Timerhanya memiliki satu utas eksekusi, sehingga tugas yang berjalan lama dapat menunda tugas lainnya. ScheduledThreadPoolExecutordapat dikonfigurasi dengan sejumlah utas. Selanjutnya, Anda memiliki kontrol penuh atas utas yang dibuat, jika Anda mau (dengan menyediakan ThreadFactory).
  • Pengecualian runtime yang dilemparkan untuk TimerTaskmembunuh satu utas itu, sehingga membuat Timermati :-( ... yaitu tugas terjadwal tidak akan berjalan lagi. ScheduledThreadExecutorTidak hanya menangkap pengecualian runtime, tetapi juga memungkinkan Anda menanganinya jika Anda mau (dengan afterExecutemetode override dari ThreadPoolExecutor). Tugas yang melempar pengecualian akan dibatalkan, tetapi tugas lain akan terus berjalan.

Jika Anda dapat menggunakannya ScheduledThreadExecutorsebagai gantinya Timer, lakukanlah.

Satu hal lagi ... sementara ScheduledThreadExecutortidak tersedia di perpustakaan Java 1.4, ada Backport JSR 166 ( java.util.concurrent) ke Java 1.2, 1.3, 1.4 , yang memiliki ScheduledThreadExecutorkelas.

Peter Štibraný
sumber
63

Jika tersedia untuk Anda, maka sulit untuk memikirkan alasan untuk tidak menggunakan kerangka kerja Java 5 executor. Panggilan:

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();

akan memberi Anda ScheduledExecutorServicefungsionalitas yang mirip dengan Timer(yaitu akan berulir tunggal) tetapi aksesnya mungkin sedikit lebih skalabel (di bawah tenda, ia menggunakan struktur bersamaan daripada sinkronisasi lengkap seperti dengan Timerkelas). Menggunakan ScheduledExecutorServicejuga memberi Anda keuntungan seperti:

  • Anda dapat menyesuaikannya jika perlu (lihat kelas newScheduledThreadPoolExecutor()atau ScheduledThreadPoolExecutor)
  • Eksekusi 'one off' dapat memberikan hasil

Satu-satunya alasan untuk tetap berpegang pada yang Timerdapat saya pikirkan adalah:

  • Ini tersedia sebelum Java 5
  • Kelas serupa disediakan di J2ME, yang dapat membuat porting aplikasi Anda lebih mudah (tetapi tidak akan terlalu sulit untuk menambahkan lapisan abstraksi yang umum dalam kasus ini)
Neil Coffey
sumber
1
Alasan lain untuk menggunakan TimerTaskmungkin ketersediaan scheduledExecutionTime()metode yang tampaknya tidak memiliki setara dalam ScheduledExecutorService.
Rohit Agarwal
3
Catatan lain: Saya menulis komentar ini dalam 2k17, tidak ada lagi J2ME. sudah mati.
msangel
1
Java Timer-class jelek.
JohnyTex
26

ExecutorService lebih baru dan lebih umum. Timer hanyalah utas yang secara berkala menjalankan hal-hal yang telah Anda jadwalkan untuk itu.

ExecutorService dapat berupa kumpulan utas, atau bahkan tersebar di seluruh sistem lain dalam sebuah kluster dan melakukan hal-hal seperti eksekusi batch satu kali, dll ...

Lihat saja apa yang masing-masing menawarkan untuk memutuskan.

Dustin
sumber
16

Berikut beberapa praktik yang lebih baik seputar penggunaan Timer:

http://tech.puredanger.com/2008/09/22/timer-rules/

Secara umum, saya akan menggunakan Timer untuk hal-hal yang cepat dan kotor dan Pelaksana untuk penggunaan yang lebih kuat.

Alex Miller
sumber
8

Dari halaman dokumentasi Oracle pada ScheduledThreadPoolExecutor

Sebuah ThreadPoolExecutor yang juga dapat menjadwalkan perintah untuk menjalankan setelah penundaan yang diberikan, atau untuk mengeksekusi secara berkala. Kelas ini lebih disukai daripada Timer ketika diperlukan beberapa thread pekerja, atau ketika fleksibilitas atau kemampuan tambahan dari ThreadPoolExecutor (yang diperluas oleh kelas ini) diperlukan.

ExecutorService/ThreadPoolExecutoratau ScheduledThreadPoolExecutorpilihan yang jelas ketika Anda memiliki banyak utas pekerja.

Pro ExecutorServicelebih dariTimer

  1. Timertidak dapat memanfaatkan core CPU yang tersedia tidak seperti ExecutorServiceterutama dengan banyak tugas menggunakan rasa ExecutorServiceseperti ForkJoinPool
  2. ExecutorServicemenyediakan API kolaboratif jika Anda memerlukan koordinasi antara beberapa tugas. Asumsikan bahwa Anda harus menyerahkan N jumlah tugas pekerja dan menunggu penyelesaiannya. Anda dapat dengan mudah mencapainya dengan invokeAll API. Jika Anda ingin mencapai hal yang sama dengan banyak Timertugas, itu tidak mudah.
  3. ThreadPoolExecutor menyediakan API yang lebih baik untuk pengelolaan siklus masa pakai Thread.

    Thread pool mengatasi dua masalah yang berbeda: mereka biasanya memberikan peningkatan kinerja ketika menjalankan sejumlah besar tugas asinkron, karena berkurangnya biaya overhead tugas per tugas, dan mereka menyediakan cara untuk mengikat dan mengelola sumber daya, termasuk utas, yang dikonsumsi saat mengeksekusi koleksi tugas. Setiap ThreadPoolExecutor juga memelihara beberapa statistik dasar, seperti jumlah tugas yang diselesaikan

    Sedikit keuntungan:

    Sebuah. Anda dapat membuat / mengelola / mengendalikan siklus hidup Thread & mengoptimalkan overhead biaya pembuatan thread

    b. Anda dapat mengontrol pemrosesan tugas (Work Stealing, ForkJoinPool, invokeAll) dll.

    c. Anda dapat memantau kemajuan dan kesehatan utas

    d. Memberikan mekanisme penanganan pengecualian yang lebih baik

Ravindra babu
sumber
5

Alasan saya kadang-kadang lebih suka Timer daripada Executors.newSingleThreadScheduledExecutor () adalah bahwa saya mendapatkan kode lebih bersih ketika saya membutuhkan timer untuk mengeksekusi pada daemon thread.

membandingkan

private final ThreadFactory threadFactory = new ThreadFactory() {
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }
};
private final ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor(threadFactory); 

dengan

private final Timer timer = new Timer(true);

Saya melakukan ini ketika saya tidak membutuhkan ketahanan dari layanan eksekutor.

Siamaster
sumber