Qualcuno può suggerirmi come posso passare un parametro a un thread?
Inoltre, come funziona per le classi anonime?
Consumer<T>
.
Qualcuno può suggerirmi come posso passare un parametro a un thread?
Inoltre, come funziona per le classi anonime?
Consumer<T>
.
Risposte:
È necessario passare il parametro nel costruttore all'oggetto Runnable:
public class MyRunnable implements Runnable {
public MyRunnable(Object parameter) {
// store parameter for later user
}
public void run() {
}
}
e invocarlo così:
Runnable r = new MyRunnable(param_value);
new Thread(r).start();
r
avrà lo stesso argomento, quindi se vogliamo passare argomenti diversi a più thread in esecuzione MyThread
avremmo bisogno di creare una nuova MyThread
istanza usando l'argomento desiderato per ogni thread. In altre parole, per ottenere un thread attivo e funzionante dobbiamo creare due oggetti: Thread e MyThread. Questo è considerato cattivo, dal punto di vista delle prestazioni?
In risposta alle modifiche alle domande, ecco come funziona per le classi anonime
final X parameter = ...; // the final is important
Thread t = new Thread(new Runnable() {
p = parameter;
public void run() {
...
};
t.start();
Hai una classe che estende Thread (o implementa Runnable) e un costruttore con i parametri che desideri passare. Quindi, quando crei il nuovo thread, devi passare gli argomenti e quindi avviare il thread, in questo modo:
Thread t = new MyThread(args...);
t.start();
Runnable è una soluzione molto migliore di Thread BTW. Quindi preferirei:
public class MyRunnable implements Runnable {
private X parameter;
public MyRunnable(X parameter) {
this.parameter = parameter;
}
public void run() {
}
}
Thread t = new Thread(new MyRunnable(parameter));
t.start();
Questa risposta è sostanzialmente la stessa di questa domanda simile: come passare i parametri a un oggetto Thread
parameter
direttamente dal run()
metodo senza usare un campo come p
quello. Sembra funzionare C'è qualcosa di sottile multithreading che mi manca non copiando parameter
in p
anticipo?
)
primo esempio
final X parameter
prima new Runnable()
, avrei potuto accedere parameter
all'interno run()
. Non avevo bisogno di fare il extra p = parameter
.
final
non è più così importante; è sufficiente che la variabile sia effettivamente definitiva (nonostante non ne faccia nulla di male)
tramite il costruttore di una classe Runnable o Thread
class MyThread extends Thread {
private String to;
public MyThread(String to) {
this.to = to;
}
@Override
public void run() {
System.out.println("hello " + to);
}
}
public static void main(String[] args) {
new MyThread("world!").start();
}
@Override
per?
@Override
afferma esplicitamente che sta sovrascrivendo il metodo astratto nella classe Thread.
Questa risposta arriva molto tardi, ma forse qualcuno la troverà utile. Si tratta di come passare un parametro (i) a una Runnable
senza nemmeno dichiarare classe nominata (utile per gli inliner):
String someValue = "Just a demo, really...";
new Thread(new Runnable() {
private String myParam;
public Runnable init(String myParam) {
this.myParam = myParam;
return this;
}
@Override
public void run() {
System.out.println("This is called from another thread.");
System.out.println(this.myParam);
}
}.init(someValue)).start();
Ovviamente puoi rimandare l'esecuzione start
ad un momento più conveniente o appropriato. E dipende da te quale sarà la firma del init
metodo (quindi potrebbero essere necessari più e / o diversi argomenti) e ovviamente anche il suo nome, ma in sostanza hai un'idea.
In effetti esiste anche un altro modo di passare un parametro a una classe anonima, con l'uso dei blocchi di inizializzazione. Considera questo:
String someValue = "Another demo, no serious thing...";
int anotherValue = 42;
new Thread(new Runnable() {
private String myParam;
private int myOtherParam;
{
this.myParam = someValue;
this.myOtherParam = anotherValue;
}
@Override
public void run() {
System.out.println("This comes from another thread.");
System.out.println(this.myParam + ", " + this.myOtherParam);
}
}).start();
Quindi tutto accade all'interno del blocco di inizializzazione.
this.myParam
allora è davvero necessario? Non potresti semplicemente eliminare le variabili private e fare riferimento alla variabile dall'ambito esterno? Capisco (ovviamente) che questo ha alcune implicazioni, come la variabile che è aperta a cambiare dopo aver iniziato il thread.
Quando si crea un thread, è necessaria un'istanza di Runnable
. Il modo più semplice per passare un parametro sarebbe passarlo come argomento al costruttore:
public class MyRunnable implements Runnable {
private volatile String myParam;
public MyRunnable(String myParam){
this.myParam = myParam;
...
}
public void run(){
// do something with myParam here
...
}
}
MyRunnable myRunnable = new myRunnable("Hello World");
new Thread(myRunnable).start();
Se poi vuoi cambiare il parametro mentre il thread è in esecuzione, puoi semplicemente aggiungere un metodo setter alla tua classe eseguibile:
public void setMyParam(String value){
this.myParam = value;
}
Una volta ottenuto questo, è possibile modificare il valore del parametro chiamando in questo modo:
myRunnable.setMyParam("Goodbye World");
Naturalmente, se vuoi attivare un'azione quando il parametro viene modificato, dovrai usare i blocchi, il che rende le cose notevolmente più complesse.
Per creare un thread normalmente si crea la propria implementazione di Runnable. Passa i parametri al thread nel costruttore di questa classe.
class MyThread implements Runnable{
private int a;
private String b;
private double c;
public MyThread(int a, String b, double c){
this.a = a;
this.b = b;
this.c = c;
}
public void run(){
doSomething(a, b, c);
}
}
Puoi estendere o e fornire i parametri come desideri. Ci sono semplici esempi nei documenti . Li porto qui:Thread
class
Runnable
class
class PrimeThread extends Thread {
long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
PrimeThread p = new PrimeThread(143);
p.start();
class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
PrimeRun p = new PrimeRun(143);
new Thread(p).start();
O scrivi una classe che implementa Runnable e passa tutto ciò di cui hai bisogno in un costruttore definito in modo appropriato, oppure scrivi una classe che estende Thread con un costruttore definito in modo appropriato che chiama super () con parametri appropriati.
A partire da Java 8, è possibile utilizzare un lambda per acquisire parametri effettivamente definitivi . Per esempio:
final String param1 = "First param";
final int param2 = 2;
new Thread(() -> {
// Do whatever you want here: param1 and param2 are in-scope!
System.out.println(param1);
System.out.println(param2);
}).start();
In Java 8 è possibile utilizzare lambda
espressioni con l' API di concorrenza e ExecutorService
come sostituto di livello superiore per lavorare direttamente con i thread:
newCachedThreadPool()
Crea un pool di thread che crea nuovi thread secondo necessità, ma riutilizza i thread precedentemente creati quando sono disponibili. Questi pool in genere miglioreranno le prestazioni dei programmi che eseguono molte attività asincrone di breve durata.
private static final ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(() -> {
myFunction(myParam1, myParam2);
});
Vedi anche executors
javadocs .
So di essere in ritardo di qualche anno, ma mi sono imbattuto in questo problema e ho adottato un approccio non ortodosso. Volevo farlo senza fare una nuova lezione, quindi questo è quello che mi è venuto in mente:
int x = 0;
new Thread((new Runnable() {
int x;
public void run() {
// stuff with x and whatever else you want
}
public Runnable pass(int x) {
this.x = x;
return this;
}
}).pass(x)).start();
Parametro che passa tramite i metodi start () e run ():
// Tester
public static void main(String... args) throws Exception {
ThreadType2 t = new ThreadType2(new RunnableType2(){
public void run(Object object) {
System.out.println("Parameter="+object);
}});
t.start("the parameter");
}
// New class 1 of 2
public class ThreadType2 {
final private Thread thread;
private Object objectIn = null;
ThreadType2(final RunnableType2 runnableType2) {
thread = new Thread(new Runnable() {
public void run() {
runnableType2.run(objectIn);
}});
}
public void start(final Object object) {
this.objectIn = object;
thread.start();
}
// If you want to do things like setDaemon(true);
public Thread getThread() {
return thread;
}
}
// New class 2 of 2
public interface RunnableType2 {
public void run(Object object);
}
È possibile derivare una classe da Runnable e durante la costruzione (diciamo) passare il parametro in.
Quindi avviarlo utilizzando Thread.start (Runnable r);
Se intendi mentre il thread è in esecuzione, tieni semplicemente un riferimento all'oggetto derivato nel thread chiamante e chiama i metodi setter appropriati (sincronizzando dove appropriato)
No, non puoi trasmettere parametri al run()
metodo. La firma ti dice che (non ha parametri). Probabilmente il modo più semplice per farlo sarebbe usare un oggetto appositamente costruito che prende un parametro nel costruttore e lo memorizza in una variabile finale:
public class WorkingTask implements Runnable
{
private final Object toWorkWith;
public WorkingTask(Object workOnMe)
{
toWorkWith = workOnMe;
}
public void run()
{
//do work
}
}
//...
Thread t = new Thread(new WorkingTask(theData));
t.start();
Una volta fatto ciò, devi fare attenzione all'integrità dei dati dell'oggetto che passi nel "WorkingTask". I dati ora esistono in due thread diversi, quindi devi assicurarti che sia sicuro per i thread.
Un'ulteriore opzione; questo approccio consente di utilizzare l'elemento Runnable come una chiamata di funzione asincrona. Se la tua attività non ha bisogno di restituire un risultato, ad esempio esegue solo alcune azioni che non devi preoccuparti di come restituisci un "risultato".
Questo modello ti consente di riutilizzare un elemento, dove è necessario un qualche tipo di stato interno. Quando non si passano i parametri nella cura del costruttore è necessario mediare l'accesso dei programmi ai programmi. Potresti aver bisogno di più controlli se il tuo caso d'uso coinvolge diversi chiamanti, ecc.
public class MyRunnable implements Runnable
{
private final Boolean PARAMETER_LOCK = false;
private X parameter;
public MyRunnable(X parameter) {
this.parameter = parameter;
}
public void setParameter( final X newParameter ){
boolean done = false;
synchronize( PARAMETER_LOCK )
{
if( null == parameter )
{
parameter = newParameter;
done = true;
}
}
if( ! done )
{
throw new RuntimeException("MyRunnable - Parameter not cleared." );
}
}
public void clearParameter(){
synchronize( PARAMETER_LOCK )
{
parameter = null;
}
}
public void run() {
X localParameter;
synchronize( PARAMETER_LOCK )
{
localParameter = parameter;
}
if( null != localParameter )
{
clearParameter(); //-- could clear now, or later, or not at all ...
doSomeStuff( localParameter );
}
}
}
Thread t = new Thread (nuovo MyRunnable (parametro)); t.start ();
Se è necessario un risultato dell'elaborazione, sarà inoltre necessario coordinare il completamento di MyRunnable al termine dell'attività secondaria. Potresti rispondere a una chiamata o semplicemente attendere sul thread 't', ecc.
Ai fini del callback di solito implemento il mio generico Runnable
con parametri di input:
public interface Runnable<TResult> {
void run(TResult result);
}
L'uso è semplice:
myManager.doCallbackOperation(new Runnable<MyResult>() {
@Override
public void run(MyResult result) {
// do something with the result
}
});
Nel gestore:
public void doCallbackOperation(Runnable<MyResult> runnable) {
new AsyncTask<Void, Void, MyResult>() {
@Override
protected MyResult doInBackground(Void... params) {
// do background operation
return new MyResult(); // return resulting object
}
@Override
protected void onPostExecute(MyResult result) {
// execute runnable passing the result when operation has finished
runnable.run(result);
}
}.execute();
}
Crea una variabile locale nella tua classe che extends Thread
o implements Runnable
.
public class Extractor extends Thread {
public String webpage = "";
public Extractor(String w){
webpage = w;
}
public void setWebpage(String l){
webpage = l;
}
@Override
public void run() {// l is link
System.out.println(webpage);
}
public String toString(){
return "Page: "+webpage;
}}
In questo modo, puoi passare una variabile quando la esegui.
Extractor e = new Extractor("www.google.com");
e.start();
Il risultato:
"www.google.com"