|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: Mar 2006
Messaggi: 2057
|
[Java] Aiuto con i Thread
ciao,
ho dei problemi a capire il funzionamento dei thread e dei metodi con esso più usati wait(), notifyAll(), e l'attributo synchronized . Per avere un esempio su cui potervi fare domande vi posto un esercizio fatto dal mio professore : (la classe console è una classe per l'ingresso e uscita ) Codice:
import java.io.*;
import java.util.*;
class Giro extends Thread {
private String parola;
private Giro next;
private int cicli;
public Giro(int cicli, String parola) {
this.parola = parola;
this.cicli = cicli;
}
public void setNext(Giro next) {
this.next = next;
}
public synchronized void aspetta() {
try {
while (!interrupted())
wait();
} catch(InterruptedException e) {}
}
public void vai() {
interrupt();
}
public void run() {
for (int i = 0; i < cicli; i++) {
aspetta();
Console.scriviStringa(parola);
next.vai();
}
}
}
class Esa {
public void fai(String nomefile) throws IOException {
Scanner sc = new Scanner(new BufferedReader(new FileReader(nomefile)));
Giro g = null, primo = null;
try {
int cicli = sc.nextInt();
Giro prev = null;
for (;;) {
String parola = sc.next();
g = new Giro(cicli, parola);
g.start();
if (prev != null)
prev.setNext(g);
prev = g;
if (primo == null)
primo = g;
}
}
catch (Exception e) {}
finally {
sc.close();
}
if (primo != null) {
g.setNext(primo);
primo.vai();
}
}
}
Codice:
import java.io.*;
class Pesa {
public static void main(String[] args) throws IOException {
String[] parole = { "primo", "secondo", "terzo" };
PrintWriter p = new PrintWriter(new FileWriter("dati.txt"));
p.println(3);
p.println("uno due tre");
p.close();
Esa esa = new Esa();
esa.fai("dati.txt");
}
}
Codice:
uno due tre uno due tre uno due tre 1- com'è possibile che ci sia il wait() nel metodo aspetta senza che da nessun'altra parte vi sia un notify() o notifyAll() ? cioè facendo cosi non si bloccano tutti i thread ? 2- poi non capisco una cosa generale dei Thread . Nelle due righe che ho scritto in rosso , vi è la creazione di un oggetto g e l'avvio del relativo thread con start() . Ecco a questo punto si avvia il thread , ma questo si bloccherà al primo wait che trova e va nella lista dei thread bloccati , e io mi chiedo : come fanno a partire gli altri Thread ? Il main resta in esecuzione nonostante partano i Thread ? Cavolo non ciò capito nulla ... Spero possiate darmi una mano ! |
|
|
|
|
|
#2 | |
|
Senior Member
Iscritto dal: Apr 2010
Città: Frosinone
Messaggi: 416
|
http://download.oracle.com/javase/1....nterrupt%28%29
Quote:
|
|
|
|
|
|
|
#3 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Tenendo in considerazione le informazioni che ti ha indicato tuccio, qua sopra, prendi carta&matita e prova a simulare l'esecuzione passo-passo del programma.
Suggerimento: il punto chiave è questo pezzo di codice del metodo fai() nella classe Esa, che si trova dopo il ciclo: Codice:
...
if (primo != null) {
g.setNext(primo);
primo.vai();
}
...
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
#4 | |
|
Senior Member
Iscritto dal: Mar 2006
Messaggi: 2057
|
Quote:
comunque ora provo a prendere carta e penna , però prima di tutto ho un dubbio . Ho provato diverse volte a simulare i risultati di programmi dove ci sono le chiamate dei thread , ma non mi è molto chiara una cosa : mettiamo che il main chiami un thread e lo avvi con il metodo start() dopo lo start() ci siano un paio di operazioni di stampa a video : pippo.start(); Console.scriviStringa("A"); Console.scriviStringa("B"); e nel run ci sia un altra stampa a video e sia dopo lo start() Consol.scriviStringa(papero); console.scriviStringa (cappello); cosa viene stampato prima e perchè ? non capisco il criterio di esecuzione del Thread . Cioè è un processo eseguito "parallelamente" al main ? So che vi faccio tante domande , ma a me non riesce imparare le cose meccaniche e quindi chiedo a voi sperando di non rompervi troppo |
|
|
|
|
|
|
#5 |
|
Senior Member
Iscritto dal: Apr 2010
Città: Frosinone
Messaggi: 416
|
se non ci sono meccanismi di sincronizzazione non puoi fare nessuna assunzione sullo scheduling
|
|
|
|
|
|
#6 | |
|
Senior Member
Iscritto dal: Mar 2006
Messaggi: 2057
|
Quote:
Sto provando a vedere i valori che stampa , però mi fermo al solito punto . Dal sito che mi avete linkato ho capito che : se arriva un interruzione su un thread che sta dormendo a causa di uno sleep() o è bloccato a causa di un wait() , viene levato lo stato d'interruzione e viene lanciata un eccezione. FIn qui ci sono ? Vi spiego passo passo come ragiono , cosi magari mi dite dove sbaglio :tramite questo ciclo , fino a quando nel file ci saranno parole verrà creato un thread per ogni parola e quando le parole finiranno verrà lanciata l'eccezione e uscirà dal for . I thread si bloccano tutti nello stato di wait() , perchè non vi sono interruzioni lanciate per ora giusto ? Codice:
for (;;) {
String parola = sc.next();
g = new Giro(cicli, parola);
g.start();
if (prev != null)
prev.setNext(g);
prev = g;
if (primo == null)
primo = g;
}
Il problema è che per me dovrebbe venir stampato : uno due tre ma non uno due tre uno due tre uno due tre Dove sbaglio ? Ultima modifica di aeroxr1 : 05-09-2010 alle 21:46. |
|
|
|
|
|
|
#7 |
|
Senior Member
Iscritto dal: Apr 2010
Città: Frosinone
Messaggi: 416
|
il terzo alla fine della sua esecuzione avvia il suo "next", che è settato così:
Codice:
if (primo != null) {
g.setNext(primo);
primo.vai();
}
il terzo thread quindi fa quello che fanno tutti gli altri, dopo aver scritto avvia il proprio next, quindi non c'è una fine a questo ciclo |
|
|
|
|
|
#8 | |
|
Senior Member
Iscritto dal: Mar 2006
Messaggi: 2057
|
Quote:
Manda l'interruzione al primo e il primo si sblocca e quindi ritorna al run , a questo punto stampa la parola e fa next.vai() sbloccando il secondo thread che a sua volta stamperà 2 e sbloccherà il terzo thread che stamperà 3 . Codice:
public synchronized void aspetta() {
try {
while (!interrupted())
wait();
} catch(InterruptedException e) {}
}
Codice:
public void run() {
for (int i = 0; i < cicli; i++) {
aspetta();
Console.scriviStringa(parola);
next.vai();
}
QUando faccio next.vai() allora riparte tutto il run del thread next ??? Se si perchè ? E come mai allora mi fa 3 stampe di uno due tre e non infinite ? Che scatole , vorrei riuscire a capire il funzionamento dei thread a modo , ma a quanto pare non è tanto semplice |
|
|
|
|
|
|
#9 | |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
Ad esempio il fatto che un Giro, ha un membro 'cicli' che viene usato nella sua implementazione del metodo 'run' appunto per controllare per quante volte ripetere il comportamento di "attendi-stampaStringa-avviaProssimoThread". Se poi esamini la classe Pesa vedrai che il file di input creato è questo: Codice:
3 uno due tre Ora forse ti è più chiaro cosa accade. Quando ti suggerivo di provare con carta&matita a simulare passo-passo il codice che hai postato, intendevo tutto il codice, non solo una parte
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
|
#10 | |
|
Senior Member
Iscritto dal: Mar 2006
Messaggi: 2057
|
Quote:
Niente non mi riesce ancora . Il fatto che in cicli ci sia 3 lo sapevo già , solo che non capisco come proceda l'esecuzione del Thread . Una volta che arriva l'interrupt ogni singolo thread parte dal punto in cui era rimasto bloccato ( grazie al fatto che arriva un interrupt nel momento in cui il thread è bloccato con wait() e quindi genera l'eccezione e esce dalla funzione aspetta() e quindi esegue il resto del run() ) e quindi fa le operazioni dopo aspetta() : public void run() { for (int i = 0; i < cicli; i++) { aspetta(); Console.scriviStringa(parola); next.vai(); } cicli vale 3 e fin qui ci siamo , poi thread uno stampa Uno e con next.vai() "sblocca" il secondo e il terzo e quindi viene stampato Uno Due Tre Ora si ritorna nuovamente al primo , però non capisco cosa faccia di preciso a questo punto : abbiamo rimandato un interrupt al primo , però la funzione aspetta() non capisco perchè venga nuovamente richiamata , cioè non capisco come faccia a sapere il compilatore che dopo l'ultimo vai si riparte da aspetta() . Forse ho capito , il motivo è : mentre faccio next.vai() , si avvia si il thread due ma il thread uno , parallelamente , continua il ciclo e ripete nuovamente aspetta() , e si riferma in attesa di un altro interrupt che gli arriva solamente quando il terzo thread rifarà next.vai() . ? Ho capito le parti in grassetto o ho preso fischi per fiaschi ? Se ho capito , mi dite un ultima cosa ? Qui aspetta è synchronized . Se esso non lo fosse , che cambierebbe ? Perchè io so che se è synchronized più thread non possono eseguire la stessa funzione contemporaneamente , però in questo caso non potrebbe anche venir omesso il synchonized ? Ultima modifica di aeroxr1 : 06-09-2010 alle 10:49. |
|
|
|
|
|
|
#11 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Sì, la svista era dovuta al fatto di non esserti reso conto che il metodo 'run' dei thread che implementa la sequenza di attesa-stampaStringa-avviaProssimo è contenuta in un ciclo
Se matita&carta tante volte sono utili, ma richiedono "troppo" tempo, puoi provare prima a usare il loro equivalente elettronico: stampare sullo standard output Ad esempio, prova a copiare e eseguire questa versione modificata del tuo codice, e ad esaminarne l'output (puoi sostituire i System.out.println() con le chiamate alla tua classe Consolle): Codice:
package concurrent;
import java.io.*;
import java.util.*;
class Giro extends Thread
{
private String parola;
private Giro next;
private int cicli;
public Giro(int cicli, String parola) {
this.parola = parola;
this.cicli = cicli;
}
public void setNext(Giro next) {
this.next = next;
}
public synchronized void aspetta() {
try {
while (!interrupted())
wait();
} catch(InterruptedException e) {}
}
public void vai() {
interrupt();
}
@Override
public void run() {
System.out.println(this.getName() + " inizio esecuzione.");
System.out.println(this.getName() + " aspetta, ciclo 0");
for (int i = 0; i < cicli; i++) {
aspetta();
System.out.println(this.getName() + " run again, ciclo " + i);
System.out.println(parola);
System.out.println(this.getName() + " lancia prossimo thread, ciclo " + i);
System.out.println(this.getName() + " aspetta, ciclo " + (i+1));
next.vai();
}
System.out.println(this.getName() + " fine esecuzione.");
}
}
class Esa
{
public void fai(String nomefile) throws IOException {
Scanner sc = new Scanner(new BufferedReader(new FileReader(nomefile)));
Giro g = null, primo = null;
try {
int cicli = sc.nextInt();
Giro prev = null;
int id = 1;
for (;;) {
String parola = sc.next();
g = new Giro(cicli, parola);
g.setName("Thread-"+id);
id = id+1;
g.start();
if (prev != null)
prev.setNext(g);
prev = g;
if (primo == null)
primo = g;
}
}
catch (Exception e) {}
finally {
sc.close();
}
if (primo != null) {
g.setNext(primo);
primo.vai();
}
}
}
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
#12 | |
|
Senior Member
Iscritto dal: Mar 2006
Messaggi: 2057
|
Quote:
Cmq ho provato ad eliminare synchronized e mi da errore . NOn capisco , il perchè . Mi deve sfuggire qualcosa sull'utilità di utilizzare synchronized in generale . COme mai è fondamentale in questo esercizio ? p.s : a lezione siccome lo spiegano cosi in 3 secondi , poi chiaramente sta a me documentarmi sui libri . Ma dovunque cerco , lo ritrovo spiegato con le solite 3 o 4 parole in fila e non riesco a capire la verà utilità del synchronized , potrei impararlo meccanicamente , ma poi che vantaggi ne trarrei ? io direi nessuni Vi ringrazio ancora per l'aiuto che mi date !!! Ultima modifica di aeroxr1 : 06-09-2010 alle 11:07. |
|
|
|
|
|
|
#13 | |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
La parola chiave syncrhonized è un meccanismo per ottenere appunto il lock intrinseco (object monitor) di un oggetto. Per farti capire meglio, l'oggetto in questione sarebbe il 'this', cioè l'stanza corrente di Giro. Ogni istanza in Java ha un 'monitor'. Per fare in modo che un thread ottenga il lock sul monitor intrinseco di un oggetto si usa appunto syncrhonized (puoi dichiarare synchronized tutto il metodo, oppure una parte specifica dentro il corpo di un metodo, con il blocco syncrhonized). Ad esempio questo: Codice:
public synchronized void aspetta() {
try {
while (!interrupted())
wait();
} catch(InterruptedException e) {}
}
Codice:
public void aspetta() {
synchronized(this) {
try {
while (!interrupted())
wait();
} catch(InterruptedException e) {}
}
}
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) Ultima modifica di banryu79 : 06-09-2010 alle 11:12. |
|
|
|
|
|
|
#14 | |
|
Senior Member
Iscritto dal: Mar 2006
Messaggi: 2057
|
Quote:
grazie !!! Te si che spieghi bene Un ultima cosa , non sarebbe mica cambiato niente se al posto della funziona vai() avessi fatto : primo.interrupt() next.interrupt() giusto ? dico giusto , ma facendo cosi mi da una stampa leggermente diversa ![]() p.s : i javadoc sono reperibili al sito che mi avete linkato in precedenza vero ? Ultima modifica di aeroxr1 : 06-09-2010 alle 11:20. |
|
|
|
|
|
|
#15 | |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
Il motivo dietro al fatto che "ti da una stampa leggermente diversa" non ha niente a che vedere col fatto di chiamare interrupt() direttamente piuttosto che tramite un metodo wrapper (fa solo quello: cioè chiama interrupt, dunque non aggiunge ne toglie nulla). Vedrai che se lanci più volte il programma otterai sempre delle leggere variazioni all'ordine di stampa, però la sincronicità tra i thread Giro per come è dichiarata nel codice sarà sempre garantita. (se poi sei veramente incuriosito puoi provare a chiedere lumi al prof, chissà...) Per ora ti consiglio di non mettere troppa carne al fuoco e di darti del tempo per digerire i nuovi concetti e magari esercitarti un po' per verificare & consolidare le conoscenze acquisite. Per i link, ecco: - Java SE 6 Documentation (documentazione varia, tra cui i javadoc che puoi anche scaricare). - The Really Big Index (compendio dei Java Tutorial, anche questi scaricabili).
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
|
#16 | |
|
Senior Member
Iscritto dal: Mar 2006
Messaggi: 2057
|
Quote:
Grazie di tutto !!! |
|
|
|
|
|
|
#17 | |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
Tanto per toglierti lo sfizio, ammesso che tu ne abbia il tempo, con un'oretta di attenta lettura puoi cominciare a intuire il perchè delle "stranezze" nell'ordine di stampa, leggendo in ordine le voci di questo tutorial: - Lesson: Concurrency E' utile per almeno aver sentito almeno una descrizione introduttiva a certi termini, concetti e alcune problematiche relative alla programmazione concorrente, sia in generale che per gli aspetti legati all'implementazione che questa assume nella tecnologia Java. In bocca al lupo per l'esame
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
|
#18 | |
|
Senior Member
Iscritto dal: Mar 2006
Messaggi: 2057
|
Quote:
Grazie ancora di tutto e crepi !!! |
|
|
|
|
|
|
#19 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Ehm, con il passaggio da Sun a Oracle e relativa riorganizzazione del sito aziendale ci ho messo un po' per capire dove trovare la pagina di accesso alla documentazione per il download: eccola
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
#20 | |
|
Senior Member
Iscritto dal: Mar 2006
Messaggi: 2057
|
Quote:
Ciao !!! |
|
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 17:36.












:







