Pertanyaan "Mengimplementasikan Runnable" vs. "memperpanjang Thread"


Dari waktu yang saya habiskan dengan utas di Java, saya menemukan dua cara ini untuk menulis untaian:

Dengan implements Runnable:

public class MyRunnable implements Runnable {
    public void run() {
        //Code
    }
}
//Started with a "new Thread(new MyRunnable()).start()" call

Atau, dengan extends Thread:

public class MyThread extends Thread {
    public MyThread() {
        super("MyThread");
    }
    public void run() {
        //Code
    }
}
//Started with a "new MyThread().start()" call

Apakah ada perbedaan yang signifikan dalam dua blok kode ini?


1794
2018-02-12 14:28


asal


Jawaban:


Ya: mengimplementasikan Runnable adalah cara yang lebih disukai untuk melakukannya, IMO. Anda tidak benar-benar mengkhususkan perilaku utas. Anda hanya memberinya sesuatu untuk dijalankan. Itu berarti komposisi adalah secara filosofis "murni" cara untuk pergi.

Di praktis istilah, itu berarti Anda dapat mengimplementasikan Runnable dan memperluas dari kelas lain juga.


1446
2018-02-12 14:32



tl; dr: mengimplementasikan Runnable lebih baik. Namun, peringatan itu penting

Secara umum, saya akan merekomendasikan menggunakan sesuatu seperti Runnable daripada Thread karena ini memungkinkan Anda untuk menjaga pekerjaan Anda hanya digabungkan secara longgar dengan pilihan konkurensi Anda. Misalnya, jika Anda menggunakan Runnable dan memutuskan kemudian bahwa ini tidak benar-benar membutuhkannya sendiri Thread, Anda bisa memanggil threadA.run ().

Peringatan: Di sini, saya sangat tidak menganjurkan penggunaan Benang mentah. Saya lebih memilih penggunaan Dapat dipanggil dan FutureTasks (Dari javadoc: "A asynchronous computation"). Integrasi timeout, pembatalan yang tepat dan penyatuan benang dari dukungan konkurensi modern semuanya jauh lebih berguna bagi saya daripada tumpukan Thread mentah.

Mengikuti: ada sebuah FutureTask konstruktor yang memungkinkan Anda untuk menggunakan Runnable (jika itu yang Anda paling nyaman dengan) dan masih mendapatkan manfaat dari alat konkurensi modern. Untuk mengutip javadoc:

Jika Anda tidak memerlukan hasil tertentu, pertimbangkan untuk menggunakan konstruksi formulir:

Future<?> f = new FutureTask<Object>(runnable, null)

Jadi, jika kita mengganti mereka runnable dengan Anda threadA, kita mendapatkan yang berikut:

new FutureTask<Object>(threadA, null)

Pilihan lain yang memungkinkan Anda untuk tetap lebih dekat dengan Runnable adalah a ThreadPoolExecutor. Anda dapat menggunakan menjalankan metode untuk lulus dalam Runnable untuk menjalankan "tugas yang diberikan kapan-kapan di masa depan."

Jika Anda ingin mencoba menggunakan kolam ulir, fragmen kode di atas akan menjadi seperti berikut ini (menggunakan Pelaksana. BaruCachedThreadPool () metode pabrik):

ExecutorService es = Executors.newCachedThreadPool();
es.execute(new ThreadA());

494
2018-02-12 14:37



Pesan moral dalam cerita:

Warisan hanya jika Anda ingin mengesampingkan beberapa perilaku.

Atau lebih tepatnya harus dibaca sebagai:

Kurang warisi, antarmuka lebih banyak.


225
2018-03-11 15:50



Nah begitu banyak Jawaban yang bagus, saya ingin menambahkan lebih banyak tentang ini. Ini akan membantu untuk mengerti Extending v/s Implementing Thread.
Memperluas mengikat dua file kelas sangat erat dan dapat menyebabkan beberapa cukup sulit untuk menangani kode.

Kedua pendekatan melakukan pekerjaan yang sama tetapi ada beberapa perbedaan.
Perbedaan paling umum adalah 

  1. Saat Anda memperpanjang kelas Thread, setelah itu Anda tidak dapat memperluas kelas lain mana pun yang Anda butuhkan. (Seperti yang Anda ketahui, Java tidak mengizinkan mewarisi lebih dari satu kelas).
  2. Ketika Anda mengimplementasikan Runnable, Anda dapat menyimpan ruang untuk kelas Anda untuk memperluas kelas lain di masa depan atau sekarang.

Namun, satu perbedaan yang signifikan antara menerapkan Runnable dan memperpanjang Thread itu
  by extending Thread, each of your threads has a unique object associated with it, whereas implementing Runnable, many threads can share the same object instance.

Contoh berikut membantu Anda untuk memahami lebih jelas

//Implement Runnable Interface...
 class ImplementsRunnable implements Runnable {

private int counter = 0;

public void run() {
    counter++;
    System.out.println("ImplementsRunnable : Counter : " + counter);
 }
}

//Extend Thread class...
class ExtendsThread extends Thread {

private int counter = 0;

public void run() {
    counter++;
    System.out.println("ExtendsThread : Counter : " + counter);
 }
}

//Use above classes here in main to understand the differences more clearly...
public class ThreadVsRunnable {

public static void main(String args[]) throws Exception {
    // Multiple threads share the same object.
    ImplementsRunnable rc = new ImplementsRunnable();
    Thread t1 = new Thread(rc);
    t1.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    Thread t2 = new Thread(rc);
    t2.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    Thread t3 = new Thread(rc);
    t3.start();

    // Creating new instance for every thread access.
    ExtendsThread tc1 = new ExtendsThread();
    tc1.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    ExtendsThread tc2 = new ExtendsThread();
    tc2.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    ExtendsThread tc3 = new ExtendsThread();
    tc3.start();
 }
}

Output dari program di atas.

ImplementsRunnable : Counter : 1
ImplementsRunnable : Counter : 2
ImplementsRunnable : Counter : 3
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1

Dalam pendekatan antarmuka Runnable, hanya satu instance dari kelas yang dibuat dan telah dibagikan oleh utas yang berbeda. Jadi nilai counter bertambah untuk setiap akses thread.

Sedangkan, pendekatan kelas Thread, Anda harus membuat instance terpisah untuk setiap akses thread. Oleh karena itu memori yang berbeda dialokasikan untuk setiap instance kelas dan masing-masing memiliki counter terpisah, nilainya tetap sama, yang berarti tidak ada kenaikan yang akan terjadi karena tidak ada referensi objek yang sama.

Kapan menggunakan Runnable?
Gunakan antarmuka Runnable ketika Anda ingin mengakses sumber daya yang sama dari grup utas. Hindari penggunaan kelas Thread di sini, karena pembuatan beberapa objek menghabiskan lebih banyak memori dan itu menjadi overhead kinerja yang besar.

Kelas yang mengimplementasikan Runnable bukanlah utas dan hanya kelas. Agar Runnable menjadi Thread, Anda perlu membuat turunan Thread dan meneruskannya sebagai target.

Dalam kebanyakan kasus, antarmuka Runnable harus digunakan jika Anda hanya berencana untuk mengganti run() metode dan tidak ada metode Thread lainnya. Ini penting karena kelas tidak boleh digolongkan kecuali programmer bermaksud memodifikasi atau meningkatkan perilaku dasar kelas.

Ketika ada kebutuhan untuk memperpanjang superclass, mengimplementasikan antarmuka Runnable lebih tepat daripada menggunakan kelas Thread. Karena kita dapat memperluas kelas lain saat mengimplementasikan antarmuka Runnable untuk membuat utas.

Saya harap ini akan membantu!


184
2018-03-05 14:26



Satu hal yang saya kaget belum disebutkan adalah penerapannya Runnable membuat kelas Anda lebih fleksibel.

Jika Anda memperpanjang ulir maka tindakan yang Anda lakukan selalu akan ada dalam utas. Namun, jika Anda menerapkan Runnable itu tidak harus terjadi. Anda dapat menjalankannya di utas, atau meneruskannya ke beberapa jenis layanan pelaksana, atau hanya menyebarkannya sebagai tugas dalam aplikasi berulir tunggal (mungkin dijalankan di lain waktu, tetapi di dalam utas yang sama). Pilihannya jauh lebih terbuka jika Anda hanya menggunakan Runnable daripada jika Anda mengikat diri Thread.


73
2018-02-12 14:51



Jika Anda ingin mengimplementasikan atau memperluas kelas lain apa pun kemudian Runnable antarmuka yang paling disukai lainnya bijaksana jika Anda tidak ingin ada kelas lain untuk memperpanjang atau menerapkannya kemudian Thread kelas lebih disukai

Perbedaan paling umum adalah

enter image description here

Ketika kamu extends Thread kelas, setelah itu Anda tidak dapat memperluas kelas lain mana pun yang Anda inginkan. (Seperti yang Anda ketahui, Java tidak mengizinkan mewarisi lebih dari satu kelas).

Ketika kamu implements Runnable, Anda dapat menghemat ruang untuk kelas Anda untuk memperluas kelas lain di masa depan atau sekarang.

  • Java tidak mendukung multiple inheritance, yang berarti Anda hanya dapat memperpanjang satu kelas di Java sehingga setelah Anda memperpanjang kelas Thread Anda kehilangan kesempatan dan tidak dapat memperpanjang atau mewarisi kelas lain di Java.

  • Dalam pemrograman berorientasi objek yang memperluas kelas umumnya berarti menambahkan fungsi baru, memodifikasi atau meningkatkan perilaku. Jika kami tidak membuat modifikasi apa pun pada Thread, gunakan antarmuka Runnable sebagai gantinya.

  • Antarmuka runnable merupakan Tugas yang dapat dijalankan baik oleh Thread biasa atau Pelaksana atau cara lainnya. pemisahan begitu logis dari Tugas sebagai Runnable daripada Thread adalah keputusan desain yang baik.

  • Memisahkan tugas sebagai Runnable berarti kita dapat menggunakan kembali tugas dan juga memiliki kebebasan untuk melaksanakannya dari berbagai cara. karena Anda tidak dapat memulai ulang Thread setelah selesai. lagi Runnable vs Thread untuk tugas, Runnable adalah pemenang.

  • Perancang Java mengakui ini dan itulah mengapa Pelaku menerima Runnable sebagai Tugas dan mereka memiliki untaian pekerja yang menjalankan tugas tersebut.

  • Mewarisi semua metode Thread adalah tambahan biaya hanya untuk mewakili Tugas yang dapat dilakukan dengan mudah dengan Runnable.

Courtesy dari javarevisited.blogspot.com

Ini adalah beberapa perbedaan penting antara Thread dan Runnable di Java, jika Anda mengetahui perbedaan lain pada Thread vs Runnable daripada membagikannya melalui komentar. Saya pribadi menggunakan Runnable over Thread untuk skenario ini dan merekomendasikan untuk menggunakan antarmuka Runnable atau Callable berdasarkan kebutuhan Anda.

Namun, perbedaan yang signifikan tersebut.

Ketika kamu extends Thread kelas, setiap utas Anda menciptakan objek unik dan dikaitkan dengannya. Ketika kamu implements Runnable, itu berbagi objek yang sama ke beberapa utas.


65
2018-05-11 08:59



Sebenarnya, tidak bijaksana untuk membandingkan Runnable dan Thread satu sama lain.

Keduanya memiliki ketergantungan dan hubungan dalam multi-threading sama seperti Wheel and Engine hubungan kendaraan bermotor.

Saya akan mengatakan, hanya ada satu cara untuk multi-threading dengan dua langkah. Biarkan saya membuat poin saya.

Runnable:
Saat menerapkan interface Runnable itu berarti Anda menciptakan sesuatu yang run able di utas yang berbeda. Sekarang membuat sesuatu yang dapat berjalan di dalam sebuah thread (runnable di dalam sebuah thread), tidak berarti membuat Thread.
Jadi kelasnya MyRunnable tidak lain adalah kelas biasa dengan void run metode. Dan benda-benda itu akan menjadi beberapa objek biasa dengan hanya sebuah metode run yang akan dieksekusi secara normal saat dipanggil. (kecuali kita mengoper objek dalam utas).

Benang:
class ThreadSaya akan mengatakan kelas yang sangat khusus dengan kemampuan memulai Thread baru yang benar-benar memungkinkan multi-threading melalui nya start() metode.

Mengapa tidak bijak untuk membandingkan?
Karena kita membutuhkan keduanya untuk multi-threading.

Untuk Multi-threading kita membutuhkan dua hal:

  • Sesuatu yang dapat berjalan di dalam Thread (Runnable).
  • Sesuatu yang dapat memulai Thread baru (Thread).

Jadi secara teknis dan teoritis keduanya diperlukan untuk memulai utas, satu kehendak menjalankan dan satu kehendak membuatnya berjalan (Seperti Wheel and Engine kendaraan bermotor).

Itu sebabnya Anda tidak dapat memulai utas dengan MyRunnable Anda harus meneruskannya ke contoh Thread.

Tapi dimungkinkan untuk membuat dan menjalankan utas hanya menggunakan class Thread karena Kelas Thread mengimplementasikan Runnable jadi kita semua tahu Thread juga adalah a Runnable dalam.

Akhirnya Thread dan Runnable saling melengkapi satu sama lain untuk multithreading bukan pesaing atau pengganti.


61
2018-05-12 13:50