Creare un eseguibile, e utilizzare il setter e getter definiti in detto eseguibile.
public class MyRunnable implements Runnable{
private volatile String myString;
public String setString(String value){this.myString = value;}
public String getString(){
return myString;
}
public void run(){}
}
Nota: la parola chiave volatile
viene utilizzata qui. La parola chiave volatile assicura se questa stringa cambia in un thread, che tutti i thread vedranno la modifica. Se invece mi assicuro che l'unico accesso all'oggetto String sia attraverso il contesto sincronizzato, la parola chiave volatile non sarebbe necessaria.
Per dimostrare il mio punto, il codice precedente e il codice di seguito sono sia thread-safe, ma sono diversi come no 2 fili possono entrare setString
e getString
simultaneamente nell'esempio che segue.
public class MyRunnable implements Runnable{
private String myString;
public synchronized String setString(String value){this.myString = value;}
public synchronized String getString(){
return myString;
}
public void run(){}
}
Un thread è in realtà solo eseguendo una eseguibile. È possibile utilizzare questo modo:
MyRunnable runnable = new MyRunnable();
Thread myThread = new Thread(runnable);
myThread.start();
String myString = runnable.getString();
Utilizzando valori atomici per primitive va bene, ma se mai desidera condividere un oggetto più complesso, si dovrà leggere su threading and synchronization.
Ad esempio:
public class Stats{
int iterations;
long runtime;
public Stats(){
iterations = 0;
runtime=0;
}
public synchronized void setIterations(int value){this.iterations = value;}
public synchronized void setRuntime(long milliseconds){
this.runtime = milliseconds;
}
public synchronized int getIterations(){
return iterations;
}
public synchronized long getRuntime(){return runtime;}
}
public class StatRunnable implements Runnable{
Stats stats;
boolean active;
public StatRunnable(){
this.active=true;
}
public Stats getStats(){
return stats;
}
long calculateRuntime(){return 0L;}
public void run(){
while(active){
//i'm synchronizing with stats to ensure no other thread alters values
//simultaneously.
synchronized(stats){
stats.setIterations(stats.getIterations()+1);
stats.setRuntime(calculateRuntime());
}
}
}
}
Questo codice mostra un esempio di sincronizzazione con oggetti non primitivi tramite la parola chiave synchronized
. L'utilizzo della parola chiave sincronizzata in una definizione di metodo blocca la classe utilizzando se stessa come oggetto di sincronizzazione.
Una nota finale, la parola chiave sincronizzata non viene solo utilizzata nelle definizioni dei metodi. Puoi usarlo per sincronizzare istanze all'interno dei metodi come ho fatto nel metodo run
in StatRunnable
.
I thread non hanno variabili. Le classi hanno membri e i metodi hanno parametri e variabili locali. Se riesegui l'analisi del problema seguendo queste linee, la risposta dovrebbe essere ovvia. – EJP