Dapat dijalankan dengan parameter?


178

Saya memiliki kebutuhan untuk "Runnable yang menerima parameter" walaupun saya tahu bahwa runnable tidak benar-benar ada.

Ini mungkin menunjukkan kelemahan mendasar dalam desain aplikasi saya dan / atau blok mental di otak saya yang lelah, jadi saya berharap untuk menemukan beberapa saran di sini tentang cara mencapai sesuatu seperti berikut, tanpa melanggar prinsip-prinsip OO mendasar:

  private Runnable mOneShotTask = new Runnable(String str) {
    public void run(String str) {
       someFunc(str);
    }
  };  

Adakah cara untuk mencapai sesuatu seperti di atas?


7
Sekarang kamu bisa menggunakannya Consumer<T>.
Alex78191

1
Saya telah membaca berbagai jawaban untuk pertanyaan ini. Sepertinya saya aneh bahwa tidak ada yang mengatakan bahwa Anda dapat menambah proyek Anda Runnables yang Anda butuhkan (dengan satu, dua, tiga atau lebih argumen) hanya menambahkan antarmuka yang sesuai. Saya membuat intisari komentar di sini untuk siapa yang tertarik: gist.github.com/jsfan3/3a66e711fd0fd233c5e4c467184adb7a
Francesco Galgani

Ini BUKAN duplikat untuk "Bagaimana saya bisa melewatkan parameter ke thread Java". Dan jawaban modernnya adalah, seperti @ Alex78191 mengatakan: useConsumer<T>
Epaga

Jawaban:


228

Sudah hampir 9 tahun sejak saya memposting ini dan sejujurnya, Java telah membuat beberapa perbaikan sejak itu. Saya akan meninggalkan jawaban asli saya di bawah, tetapi tidak perlu bagi orang untuk melakukan apa yang ada di dalamnya. 9 tahun yang lalu, selama tinjauan kode saya akan mempertanyakan mengapa mereka melakukannya dan mungkin menyetujuinya, mungkin tidak. Dengan lambda modern tersedia, itu tidak bertanggung jawab untuk memiliki jawaban yang sangat tinggi merekomendasikan pendekatan kuno (yang, pada semua keadilan, meragukan untuk memulai dengan ...) Di Jawa modern, bahwa tinjauan kode akan segera ditolak, dan ini akan menjadi menyarankan:

void foo(final String str) {
    Thread t = new Thread(() -> someFunc(str));
    t.start();
}

Seperti sebelumnya, detail seperti menangani utas itu dengan cara yang bermanfaat dibiarkan sebagai latihan bagi pembaca. Tapi terus terang, jika Anda takut menggunakan lambdas, Anda harus lebih takut dengan sistem multi-threaded.

Jawaban asli, hanya karena:

Anda bisa mendeklarasikan kelas tepat di metode

void Foo(String str) {
    class OneShotTask implements Runnable {
        String str;
        OneShotTask(String s) { str = s; }
        public void run() {
            someFunc(str);
        }
    }
    Thread t = new Thread(new OneShotTask(str));
    t.start();
}

Terima kasih semua! Semua solusi yang disarankan menunjuk ke pendekatan yang sama tetapi saya hanya bisa menerimanya. Saya pasti sangat lelah karena tidak bisa membuat ini sendiri. +1 untuk semua.
uTubeFan

18
Sebenarnya, kebanyakan orang tidak tahu Anda bisa mendeklarasikan kelas di dalam suatu metode. Beberapa orang akan menganggapnya sebagai gaya yang buruk. Saya kira ini masalah selera. :)
corsiKa

3
antarmuka publik ResultRunnable <T> {public void run (hasil T); }
Roman M

46

Anda bisa memasukkannya ke dalam fungsi.

String paramStr = "a parameter";
Runnable myRunnable = createRunnable(paramStr);

private Runnable createRunnable(final String paramStr){

    Runnable aRunnable = new Runnable(){
        public void run(){
            someFunc(paramStr);
        }
    };

    return aRunnable;

}

(Ketika saya menggunakan ini, parameter saya adalah ID integer, yang saya gunakan untuk membuat hashmap ID -> myRunnables. Dengan begitu, saya bisa menggunakan hashmap untuk memposting / menghapus objek myRunnable yang berbeda di dalam handler.)


3
Terima kasih telah berbagi kode - Saya suka ketika orang melakukannya bukan hanya mengoceh. Satu pertanyaan - apakah pendekatan di atas OK ketika datang ke Memory Leaking? Semua referensi yang Anda lewati akan dibuang dengan benar?
nikib3ro

2
@ kape123 Jawabannya adalah "itu tergantung". Selama Runnableobjek yang dikembalikan oleh metode ada di mana saja, paramStrmungkin tidak akan memenuhi syarat untuk pengumpulan sampah. Ada kemungkinan bahwa jika objek ada tetapi tidak pernah dapat dijalankan lagi, JIT (atau bahkan javac) dapat memutuskan untuk menghapusnya dari ruang lingkup, tetapi kita tidak boleh mengandalkan optimisasi tersebut karena mereka dapat berubah di masa depan.
corsiKa

"Terima kasih telah berbagi kode - saya suka ketika orang melakukan itu, bukan hanya mengoceh." - apa?
Rob Grant

30
theView.post(new Runnable() {
    String str;
    @Override                            
    public void run() {
        par.Log(str);                              
    }
    public Runnable init(String pstr) {
        this.str=pstr;
        return(this);
    }
}.init(str));

Buat fungsi init yang mengembalikan objek itu sendiri dan menginisialisasi parameter dengannya.


1
Sayangnya Anda tidak akan dapat menetapkannya ke variabel dan memanggil init ()
Andrew Glukhoff

11

Saya menggunakan kelas berikut yang mengimplementasikan antarmuka Runnable . Dengan kelas ini Anda dapat dengan mudah membuat utas baru dengan argumen

public abstract class RunnableArg implements Runnable {

    Object[] m_args;

    public RunnableArg() {
    }

    public void run(Object... args) {
        setArgs(args);
        run();
    }

    public void setArgs(Object... args) {
        m_args = args;
    }

    public int getArgCount() {
        return m_args == null ? 0 : m_args.length;
    }

    public Object[] getArgs() {
        return m_args;
    }
}

2
Bagaimana Anda menggunakan kelas abstrak ini untuk menjalankan runnable dengan parameter?
EZDsIt

Saya lebih suka menggunakan konstruktor dengan parameter (s) public RunnableArg(Object... args) { setArgs(args); } kemudian menggambarkan kelas lokal: class ActionArg extends RunnableArg { public ActionArg(Object... arg) { super(arg); } @Override public void run() { /* getArgs() and process them */ } } dan menggunakannya Thread t = new Thread(new ActionArg( %param_object(s)% )); t.start();
GSD.Aaz



5

Pertama-tama saya ingin tahu apa yang ingin Anda capai di sini sehingga perlu argumen untuk diteruskan ke Runnable baru () atau untuk menjalankan (). Cara biasa seharusnya memiliki objek Runnable yang meneruskan data (str) ke utasnya dengan mengatur variabel anggota sebelum memulai. Metode run () kemudian menggunakan nilai-nilai variabel anggota ini untuk melakukan eksekusi someFunc ()

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.