Thread

di Michele Genchi il
39 risposte
Ciao ragazzi, vi contatto perchè ho del codice freaco da mostrare e chiedere un Vostro parere.
Premetto che é un codice scopiazzato e non capisco però cosa accade?

public class Synch {
public static void main(String[] args) {
// TODO Auto-generated method stub
CallMe target = new CallMe();
new Caller(target, "Hello");
new Caller(target, "Synchronized");
new Caller(target, "World");
} }

public class Caller implements Runnable {
private String msg;
private CallMe target;
public Caller(CallMe t, String s) {
target = t;
msg = s;
new Thread(this).start();
}
public void run() {
// TODO Auto-generated method stub
//synchronized(target){
target.call(msg);
//}
}
}
public class CallMe {
/*synchronized*/ public void call(String msg) {
System.out.print("[" + msg);
try {
Thread.sleep(1000);
}
catch (Exception e){}
System.out.println("]");
}
}
Output senza sincronizzazione Output con sincronizzazione
[Hello[Synchronized[World] [Hello]
] [Synchronized]
] [World]

39 Risposte

  • Ora cosa é successo!!!
    a me da come risultato output quello non sincronizzato

    come si fa a passare a quello sincronizzato?
  • Michele Genchi ha scritto:


    Ciao ragazzi, vi contatto perchè ho del codice freaco da mostrare e chiedere un Vostro parere.
    Premetto che é un codice scopiazzato e non capisco però cosa accade?
    La questione è questa: ci sono 3 thread e c'è un oggetto "condiviso" che è facile da vedere e capire perché lo stesso oggetto CallMe viene passato ai tre oggetti Caller.

    Il run() del thread fa nient'altro che invocare call sul CallMe condiviso. E il call del CallMe stampa il messaggio, attende un po' e poi stampa "]".

    Ora, senza alcun tipo di accorgimento, siccome la esecuzione e le tempistiche dei thread sono molto aleatorie e dipendono da molti fattori, allora può capitare che i tre messaggi vengano stampati in qualunque ordine e pure che i due print/println siano "intermixati" tra i thread.

    Ovvero es.:

    print di "[Hello"
    print di "[World"
    println di "]" (relativo al thread di Hello)
    println di "]" (relativo al thread di World)

    Michele Genchi ha scritto:


    come si fa a passare a quello sincronizzato?
    Dipende sincronizzato per ottenere che cosa. Non basta dire solo "sincronizzato".

    Se il tuo interesse è far in modo che [messaggio] venga stampato così per intero senza alcun disturbo tra i vari thread, allora è sufficiente rendere "atomico" il call(). E questo si può fare ottenendo il lock (da parte di ciascun thread per volta) sull'oggetto condiviso che è il CallMe.
    Quindi si può rendere call synchronized oppure acquisire esplicitamente il lock sul target.

    Che è appunto la parte commentata.

    Se invece intendi ottenere una certa sequenzialità particolare (es. che [Hello] venga sempre stampato prima di [Synchronized]), allora è un altro discorso. E non basta un banale synchronized.
  • Sincronizzato
    [Hello]
    [Synchronized]
    [World]
  • Michele Genchi ha scritto:


    sincronizzato
    [Hello]
    [Synchronized]
    [World]
    Se call è solo "atomico" anche questo output

    [World]
    [Synchronized]
    [Hello]

    è possibile. O qualunque altra sequenza.
  • Sul libro che sto studiando c'era quel codice e come output dava:
    sincronizzato
    [Hello]
    [Synchronized]
    [World]
    Non sincronizzato
    [Hello[Synchronized[World]
    ]
    ]

    Copiato ed incollato, a me da come output solo il non sincronizzato.
    L'altro me lo da se faccio il debug
  • Michele Genchi ha scritto:


    Copiato ed incollato, a me da come output solo il non sincronizzato.
    L'altro me lo da se faccio il debug
    Ti ripeto (l'ho detto prima), che se vuoi solo aver call() "atomico", è sufficiente:

    il synchronized sul metodo call
    O
    il synchronized(target) al blocco che invoca call.

    E queste sono appunto le parti "commentate" del codice.
  • Okay, ho capito ora, grazie
  • Grazie al tuo suggerimento e aiuto ho capito bene il thread e l'ho applicato ad un giochino di dadi
  • Si continua con lo studio, adesso sto facendo i metodi wait e notify della classe thread
    Ed ho pensato di fare una simulazione di un semaforo per eaercitazione... Che mi dite? È fattibile? e che suggerimenti avete in merito?
    Volevo tenere pronti i tre colori del semaforo e mettere in pausa i colori spenti... Mmmh veramente volevo arrivarci da solo, ma qlk piccolo consiglio è bene accetto
  • Michele Genchi ha scritto:


    adesso sto facendo i metodi wait e notify della classe thread
    Nota che wait/notify/notifyAll sono di Object, ovvero qualunque oggetto li ha.

    Michele Genchi ha scritto:


    Ed ho pensato di fare una simulazione di un semaforo per eaercitazione... Che mi dite? È fattibile? e che suggerimenti avete in merito?
    Volevo tenere pronti i tre colori del semaforo e mettere in pausa i colori spenti... Mmmh veramente volevo arrivarci da solo, ma qlk piccolo consiglio è bene accetto
    Sì, è possibile. Ma prima magari fai un esercizio interessante.
    Nel codice sopra, anche se usi il synchronized le stringhe Hello Synchronized World possono essere stampate in qualunque ordine. Il synchronized garantisce solo atomicità e mutua esclusione. Non garantisce nulla sulla sequenzialità dei thread.
    Usa wait/notifyAll per assicurare una certa sequenza delle scritte.
  • Si caro, hai ragione object, e sono ereditate da tutte le sottoclassi, cmq in questo caso; correggimi se sbaglio, è applicato alla classe thread...
    Okay come primo esercizio modificò quello che hai detto tu e magari do una ricontrollato al gioco dei dadi...
    Mmmh ma almeno sto migliorando o devo cambiare mestiere?
  • SCJP 5 (91%) – SCWCD 5 (94%)
    complimenti Andrea , ecco perché sentivo di parlare con una persona preparata,
    a volte ho paura però a confrontarmi con persone come te

    ho provato l'esercizio che mi hai detto:
    public class CallMe {
    boolean pausa;
    synchronized public void call(String msg,boolean p) {
    pausa=p;
    System.out.print("[" + msg);
    if (!pausa)
    try {
    Thread.sleep(2000);
    System.out.println("]");
    pausa=true;
    wait(); }
    catch (Exception e){}
    else { notifyAll(); }
    }
    }
    In fase di debug cerco di capire cosa accade !!! ma non risulta granché
  • Michele Genchi ha scritto:


    Si caro, hai ragione object, e sono ereditate da tutte le sottoclassi, cmq in questo caso; correggimi se sbaglio, è applicato alla classe thread...
    No, non c'entra direttamente con un java.lang.Thread, cioè non c'è nulla di speciale nel suo riguardo. wait/notify/notifyAll sono di qualunque oggetto. Anche un oggetto java.lang.Thread alla fin fine .. è un oggetto, quindi anche su di esso si può acquisire il lock e poi usare i 3 metodi citati. (io però non andrei mai ad usare un java.lang.Thread come lock/condition-queue)

    Michele Genchi ha scritto:


    public class CallMe {
    boolean pausa;
    	synchronized public void call(String msg,boolean p) {
    		pausa=p;
    		System.out.print("[" + msg);
    			if (!pausa) 
    				try {
    					Thread.sleep(2000);
    					System.out.println("]");
    					pausa=true;
    					wait();				}
    				catch (Exception e){}
    			else { notifyAll(); }
    	}
    }
    No, non basta (e non è nemmeno proprio corretto) per imporre una sequenzialità ai thread in modo da stampare i messaggi in un ben preciso ordine.

    Ci sono (sicuramente) diversi modi di realizzare questa cosa. Ne dico giusto uno:

    Si può dare agli oggetti Caller un numero progressivo, es. il primo Caller 0, il secondo 1, ecc...
    Poi in CallMe si mette una variabile di istanza che tiene il numero relativo al Caller che deve essere lasciato "passare" per stampare il messaggio.
    Poi quando in Caller invochi il call di CallMe, oltre a passare il messaggio passi anche il numero del Caller.
    Se in CallMe il numero da lasciar passare è 0, vuol dire che il Caller 0 deve poter stampare il messaggio mentre gli altri Caller (anche se dovessero arrivare prima in quel punto) devono bloccarsi e stare in attesa.
    Una volta stampato il messaggio, incrementi il numero (in modo che il Caller successivo possa passare) e fai notifyAll().

    Ricordati che il wait() andrebbe sempre fatto dentro un ciclo (tipicamente un while) che deve testare una condizione che è quella che deve "reggere" affinché il thread stia in attesa.

    Prova con queste indicazioni.
  • Okay grazie, per il simulatore del semaforo aspetto, faccio prima questo... Anche perché simulare 4 semafori ad un incrocio è complicato...
Devi accedere o registrarti per scrivere nel forum
39 risposte