Thread

di il
39 risposte

39 Risposte - Pagina 2

  • Re: Thread

    Cos'ì intendevi dire?

    public class CallMe {
    int conta=0;

    synchronized public void Call(String msg,int np) {
    System.out.print("["+msg);
    while (conta==0) {
    try {
    Thread.sleep(2000);
    System.out.println("]");
    wait();
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    conta++;
    notifyAll();
    }
    }
    }
  • Re: Thread

    Michele Genchi ha scritto:


    Cos'ì intendevi dire?
    Purtroppo no. Non è corretto e non stai nemmeno usando il parametro 'np'
  • Re: Thread

    Okay, ci lavoro ancora su... Per mia esperienza, su altri linguaggi, so che l'unico modo per imparare e sbattere sul codice
  • Re: Thread

    Mmmh sto wait e notify mi sta creando problemi seri...
    Ricapitolando con wait blocco l'esecuzione al thread corrente e non permetto ad altri thread di partire
    Con notify() notificò che ora può partire il thread ma nel mio caso particolare deve partire quello successivo.
    Mmmh me lo spiegheresti tu?
  • Re: Thread

    Michele Genchi ha scritto:


    Mmmh sto wait e notify mi sta creando problemi seri...
    Guarda, adesso stai pensando che è complicato ma ti assicuro che è molto più semplice di quello che pensi!
    Se proprio non riesci, posso postarti (appena riesco) la "mia" soluzione e te la spiego. Se invece vuoi continuare a pensarci, posso darti qualche altro indizio.
  • Re: Thread

    Mah.. Non so,
    Innanzitutto wait() blocca il thread che in esecuzione in modo che non partono altri in modo casuale
    Notify() notifica al successivo thread che può andare in esecuzione
    Questo è giusto? Dopodiché che consigli avresti da d'armi e se faccio la figura di non capirlo di nuovo?
  • Re: Thread

    Michele Genchi ha scritto:


    Innanzitutto wait() blocca il thread che in esecuzione in modo che non partono altri in modo casuale
    Notify() notifica al successivo thread che può andare in esecuzione
    Questo è giusto?
    wait() mette in sospensione il thread corrente (che lo sta invocando) ma attenzione rilascia il lock. Questo è fondamentale, altrimenti un altro thread non potrebbe acquisire quel medesimo lock e fare un notify!
    notify()/notifyAll() risvegliano rispettivamente un solo thread (e nota, uno a caso) o tutti i thread in attesa su quella condition-queue (relativa al lock, ecco perché deve essere lo stesso).

    Quando dici "Notify() notifica al successivo thread" in realtà il notify non sa assolutamente quale deve essere il successivo. Questo è la logica di attesa nel call che lo stabilisce, basandosi appunto su quel numero.

    Comunque te lo dico subito: in questo caso ci serve il notifyAll(), non il notify().
  • Re: Thread

    Se rilascia il lock vuol dire che é stato precedentemente messo in lock;
    - la mutua esclusione che mette in stato di lock un thread
    - il wait viene considerata una sorta di pausa perché nessun thread può partire
    - se viene lanciato il notify dopo che il lock é stato rilasciato permette di eseguire a caso un altro thread;
    diciamo che fine qui con la logica ci sono, ora bisogna determinare quale thread lanciare per rispettare l'ordine delle stringhe:
    [Hello]
    [Synchronized]
    [World]
  • Re: Thread

    Michele Genchi ha scritto:


    Se rilascia il lock vuol dire che é stato precedentemente messo in lock;
    Certo. La regola fondamentale: wait/notify/notifyAll vanno sempre invocati su un oggetto di cui il thread corrente ha acquisito il lock. Quindi vanno fatti dentro un metodo synchronized o un blocco synchronized.

    Michele Genchi ha scritto:


    - la mutua esclusione che mette in stato di lock un thread
    Uhm, detto così non vuol dire granché.
    Attenzione che un thread che attende per acquisire un lock è una cosa diversa da uno sleep(), un join() o un wait().

    Comunque già che ci sono aggiungo una cosa: quando un thread è sospeso, in attesa, dentro un wait() e un altro thread lo risveglia, esso esce dal wait ma deve comunque riacquisire il lock. Perché appunto si trova nel contesto di un blocco synchronized. Questo non è automatico, cioè non lo riacquisisce immediatamente e solo perché si sveglia. Deve comunque "competere" con altri thread che eventualmente tentano pure loro di acquisirlo! Quindi potrebbe anche non avvenire subito.

    Michele Genchi ha scritto:


    diciamo che fine qui con la logica ci sono, ora bisogna determinare quale thread lanciare per rispettare l'ordine delle stringhe:
    Ogni oggetto Caller ha il suo proprio numero fisso (es. 0 o 1 o 2). E nell'oggetto CallMe viene mantenuto il numero che man mano indica il thread del Caller deve poter passare subito nel call piuttosto che rimanere bloccato.
    Il nocciolo, te lo ripeto, è tutto solo qui. Nella condizione che è quella che deve "reggere" per far stare in wait il thread.
  • Re: Thread

    A parte che la cosa mi viene cmq difficle
    sarebbe pi+ corretta una scala di priorità o il metodo che mi hai suggerito?
    cmq si vede che é un argomento avanzato...
    non puoi trasferire 1/4 del tuo cervello a me e così risolvo la metà dei mei pronlemi:-(
    aspetta e sei buono e paziente e mi aiuti altrimenti chissà dov'ero?

    Detto questo ci rinuncio... magari vedendo il codice mi verrà facile capirlo
  • Re: Thread

    Ok, allora ecco svelato il codice!

    Innanzitutto la seguente è la versione senza wait/notify. Ho solo preso il tuo codice nel post iniziale, l'ho scritto/pulito meglio ed ho aggiunto uno sleep di durata "casuale" prima del call().
    public class Synch {
        public static void main(String[] args) {
            CallMe target = new CallMe();
            new Caller(target, "Hello");
            new Caller(target, "Synchronized");
            new Caller(target, "World");
        }
    }
    
    class Caller implements Runnable {
        private CallMe target;
        private String msg;
    
        public Caller(CallMe target, String msg) {
            this.target = target;
            this.msg = msg;
            new Thread(this).start();
        }
    
        public void run() {
            try {
                Thread.sleep((long) (40 * Math.random()));
            } catch (Exception e) {}
    
            target.call(msg);
        }
    }
    
    class CallMe {
        public synchronized void call(String msg) {
            System.out.print("[" + msg);
            try {
                Thread.sleep(1000);
            } catch (Exception e) {}
            System.out.println("]");
        }
    }
    Ho aggiunto lo sleep casuale perché senza di questo, e dipendentemente dal S.O./piattaforma e dalle logiche di scheduling dei thread, è possibile (e nemmeno troppo difficile) che l'output Hello Synchronized World sia "quasi" sempre questo.

    Con lo sleep casuale invece è altamente più probabile che l'output vari anche da una esecuzione all'altra. Prova ad avviarlo un po' di volte (es. una decina) e lo vedrai tu stesso.

    Ora aggiungo al codice sopra solo alcune cose:
    - un "index" in Caller (quindi variabile di istanza, modifica al costruttore, ecc..)
    - un "currentIndex" nel CallMe con i wait/notifyAll nel call()
    public class Synch {
        public static void main(String[] args) {
            CallMe target = new CallMe();
            new Caller(target, 0, "Hello");
            new Caller(target, 1, "Synchronized");
            new Caller(target, 2, "World");
        }
    }
    
    class Caller implements Runnable {
        private CallMe target;
        private int index;
        private String msg;
    
        public Caller(CallMe target, int index, String msg) {
            this.target = target;
            this.index = index;
            this.msg = msg;
            new Thread(this).start();
        }
    
        public void run() {
            try {
                Thread.sleep((long) (40 * Math.random()));
            } catch (Exception e) {}
    
            target.call(index, msg);
        }
    }
    
    class CallMe {
        private int currentIndex = 0;
    
        public synchronized void call(int index, String msg) {
            try {
                while (index != currentIndex) {
                    wait();
                }
            } catch (InterruptedException e) {
                System.err.println(e);
                return;
            }
    
            System.out.print("[" + msg);
            try {
                Thread.sleep(1000);
            } catch (Exception e) {}
            System.out.println("]");
    
            currentIndex++;
            notifyAll();
        }
    }
    Ora l'output è sempre quello dettato dalla sequenza 0 1 2. Puoi anche provare a costruire i Caller passando i numeri con un'altra sequenza e vedrai che l'output seguirà quella!

    Il catch di InterruptedException è solo un pro-forma che nel caso della applicazione non dovrebbe mai capitare.

    Se non è chiaro ... spiego!
  • Re: Thread

    @Michele, trovi le difficolta' perche' stai utilizzando delle primitive di sincronizzazione ad un livello troppo basso! E ti stai perdendo in dettagli!
  • Re: Thread

    migliorabile ha scritto:


    @Michele, trovi le difficolta' perche' stai utilizzando delle primitive di sincronizzazione ad un livello troppo basso! E ti stai perdendo in dettagli!
    Ma scusa ... se sta imparando, sono anche queste le cose che deve comprendere e da cui deve partire per qualunque altra cosa più complessa.
    Ed è per questo che gli sto spiegando queste cose e non ci vedo nulla di strano in questo!
  • Re: Thread

    L'avevo fatto così ma in modo garbugliato e contorto... Mah allora c'ero arrivato... Si avevo intuito che servisse sugli eventi ma voglio fare le cose con calma... Grazie davvero Tanto,...
    si così si rispetta la cronologia perché c'è un indice da rispettare... ..
  • Re: Thread

    Michele Genchi ha scritto:


    L'avevo fatto così ma in modo garbugliato e contorto... Mah allora c'ero arrivato...
    Bene. Ti è anche chiaro perché in questo caso non si può usare solo notify() ma serve davvero il notifyAll() ?
Devi accedere o registrarti per scrivere nel forum
39 risposte