Eseguibile con un parametro?


178

Ho bisogno di un "Runnable che accetta un parametro" anche se so che tale runnable non esiste davvero.

Ciò può indicare un difetto fondamentale nella progettazione della mia app e / o un blocco mentale nel mio cervello stanco, quindi spero di trovare qui alcuni consigli su come realizzare qualcosa di simile al seguente, senza violare i principi fondamentali di OO:

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

Qualche idea su come realizzare qualcosa di simile a quanto sopra?


7
Adesso puoi usare Consumer<T>.
Alex78191,

1
Ho letto le varie risposte a questa domanda. Mi sembra strano che nessuno abbia detto che puoi aggiungere al tuo progetto i Runnables di cui hai bisogno (con uno, due, tre o più argomenti) semplicemente aggiungendo un'interfaccia appropriata. Ho creato un commento commentato qui per chi è interessato: gist.github.com/jsfan3/3a66e711fd0fd233c5e4c467184adb7a
Francesco Galgani

Questo NON è un duplicato di "Come posso passare un parametro a un thread Java". E la risposta moderna è, come dice @ Alex78191: usareConsumer<T>
Epaga il

Risposte:


228

Beh, sono passati quasi 9 anni da quando ho pubblicato questo post e, ad essere sinceri, Java ha apportato un paio di miglioramenti da allora. Lascerò la mia risposta originale qui sotto, ma non c'è bisogno che le persone facciano quello che c'è dentro. 9 anni fa, durante la revisione del codice avrei messo in dubbio il motivo per cui l'hanno fatto e forse l'hanno approvato, forse no. Con i lambda moderni disponibili, è irresponsabile avere una risposta così votata che consigli un approccio antiquato (che, in tutta onestà, era discutibile per cominciare ...) Nella moderna Java, quella revisione del codice sarebbe stata immediatamente respinta, e questo sarebbe suggerito:

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

Come in precedenza, dettagli come la gestione di quel thread in modo significativo vengono lasciati come esercizio al lettore. Ma per dirla senza mezzi termini, se hai paura di usare lambda, dovresti avere ancora più paura dei sistemi multi-thread.

Risposta originale, solo perché:

Puoi dichiarare una classe nel metodo

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();
}

Grazie a tutti! Tutte le soluzioni suggerite indicano lo stesso approccio, ma posso accettarne solo uno. Devo essere molto stanco di non riuscire a inventarmelo da solo. +1 a tutti.
uTubeFan

18
In realtà, molte persone non sanno che puoi dichiarare una classe all'interno di un metodo. Alcuni lo considererebbero uno stile scadente. Immagino sia una questione di gusti. :)
corsiKa

3
interfaccia pubblica ResultRunnable <T> {public void run (risultato T); }
Roman M

46

Potresti metterlo in una funzione.

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;

}

(Quando l'ho usato, il mio parametro era un ID intero, che ho usato per creare una hashmap di ID -> myRunnables. In questo modo, posso usare l'hashmap per pubblicare / rimuovere diversi oggetti myRunnable in un gestore.)


3
Grazie per aver condiviso il codice: adoro quando le persone lo fanno invece di chiacchierare. Una domanda: l'approccio sopra è OK quando si tratta di perdite di memoria? Tutti i riferimenti che passi saranno eliminati correttamente?
nikib3ro,

2
@ kape123 La risposta è "dipende". Finché un Runnableoggetto restituito dal metodo esiste ovunque, paramStrprobabilmente non sarà idoneo per la garbage collection. È possibile che se l'oggetto esiste ma non può mai essere eseguito di nuovo, JIT (o anche javac) potrebbe decidere di rimuoverlo dall'ambito, ma non dovremmo fare affidamento su tali ottimizzazioni perché potrebbero cambiare in futuro.
corsiKa

"Grazie per aver condiviso il codice: adoro quando le persone lo fanno invece di chiacchierare." - che cosa?
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));

Crea la funzione init che restituisce l'oggetto stesso e inizializza i parametri con esso.


1
Sfortunatamente non sarà possibile assegnarlo a una variabile e chiamare init ()
Andrew Glukhoff

11

Uso la seguente classe che implementa l' interfaccia Runnable . Con questa classe puoi facilmente creare nuovi thread con argomenti

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
Come useresti questa classe astratta per eseguire un file eseguibile con un parametro?
EZDsIt

Preferisco usare il costruttore con i parametri, public RunnableArg(Object... args) { setArgs(args); } quindi descrivere la classe locale: class ActionArg extends RunnableArg { public ActionArg(Object... arg) { super(arg); } @Override public void run() { /* getArgs() and process them */ } } e usarlo Thread t = new Thread(new ActionArg( %param_object(s)% )); t.start();
GSD.Aaz,



5

Vorrei prima sapere cosa stai cercando di realizzare qui per avere bisogno di un argomento da passare a nuovo Runnable () o run (). Il modo normale dovrebbe essere quello di avere un oggetto Runnable che passi i dati (str) ai suoi thread impostando le variabili membro prima di iniziare. Il metodo run () utilizza quindi questi valori delle variabili membro per eseguire someFunc ()

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.