Mettere in attesa un Thread

di il
1 risposte

Mettere in attesa un Thread

Ciao a tutti,
Ho una coda che viene riempita mano a mano da un Thread ed ho un secondo Thread che dovrebbe restare in attesa quando la coda è vuota e attivarsi con delle letture non appena la coda si riempie di un elemento...
come faccio a mettere in attesa un Thread finché la coda non viene riempita da almeno un elemento??
Penso si debba usare un wait però non capisco bene come.

Grazie

1 Risposte

  • Re: Mettere in attesa un Thread

    Ciao, per fare quello che dici bisogna che i due Thread siano in sincronia altrimenti si perdono valori. Per farti capire come fare ti metto un esempio di codice composto da quattro classi, ecco a cosa servono:

    Main: è la classe da dove parte l'applicazione, vengono istanziati i Thread e un'altra classe;

    ProduceInteger: è il Thread che produce il valore che il secondo Thread deve leggere;

    ConsumeInteger: è il Thread che legge il valore prodotto da ProduceInteger;

    HoldIntegerSynchronized: è la classe che permette di settare e leggere il valore condiviso (un intero).

    Prima di darti il codice ti spiego in linea di massima come funziona:
    L'applicazione parte nella classe Main, li vengono create le istanze di tutte le classi, in particolare l'istanza di HoldIntegerSynchronized viene passata come argomento ai due Thread, in questo modo fanno riferimento allo stesso oggetto.
    ProduceInteger si occupa di richiamare il metodo setSharedInt contenuto in HoldIntegerSynchronized, mentre ConsumeInteger si occupa di richiamare il metodo getSharedInt contenuto in HoldIntegerSynchronized.
    I due Thread vanno in pausa per un tempo casuale tramite Thread.sleep((int) (Math.random() * 3000)); questo fa si che non si sa quando uno legge e l'altro scrive.
    Il codice che effettua la sincronia e quindi i controlli è contenuto nella classe HoldIntegerSynchronized, ma cosa succede? Supponiamo che ProduceInteger ha settato il valore dell'intero ora deve leggerlo ConsumeInteger, ma per sfortuna ProduceInteger va a richiamare il metodo setSharedInt mentre ConsumeInteger è in sleep, ma è qui che scatta le sincronia infatti grazie ad una variabile boolean di controllo il Thread che ha chiamato quel metodo va in wait(); non appena ConsumeInteger prenderà il valore chiamerà notify(); che fa si che il Thread in wait venga ripristinato e quindi torni in esecuzione.
    Da notare che il metodo getSharedInt chiama notify() prima che ritorni il valore, e che succede se in pochi istanti il metodo setSharedInt torna in esecuzione e quindi cambia il valore dell'intero? Sembrerebbe che il codice non funziona ma è qui che interviene la parola magica synchronized che messa nella dichiarazione del metodo fa si che in un oggetto venga eseguito un solo metodo synchronized alla volta. Sono stato chiaro? Spero di si, ecco il codice:

    classe Main:
    
    /**
     *
     * @author Luigi
     */
    public class Main {
    
        public static void main(String[] args)
            {
                HoldIntegerSynchronized sharedObject = new HoldIntegerSynchronized();
    
                ProduceInteger producer = new ProduceInteger(sharedObject);
    
                ConsumeInteger consumer = new ConsumeInteger(sharedObject);
    
                producer.start();
                consumer.start();
            }
    
    }
    
    Classe ProduceInteger:
    
    /**
     *
     * @author Luigi
     */
    public class ProduceInteger extends Thread
        {
            private HoldIntegerSynchronized sharedObject;
    
            public ProduceInteger(HoldIntegerSynchronized shared)
                {
                    super("ProduceInteger");
                    sharedObject = shared;
                }
    
            public void run()
                {
                    for(int count = 1; count <= 10; count++ )
                        {
                            try
                                {
                                    Thread.sleep((int) (Math.random() * 3000));
                                }
                            catch(InterruptedException exception)
                                {
                                    System.err.println(exception.toString());
                                }
    
                            sharedObject.setSharedInt(count);
                        }
    
                    System.err.println(getName() + " fine produzione valori" + "\nTermino " + getName());
                }
        }
    
    Classe ConsumeInteger:
    
    /**
     *
     * @author Luigi
     */
    public class ConsumeInteger extends Thread
        {
            private HoldIntegerSynchronized sharedObject;
    
            public ConsumeInteger(HoldIntegerSynchronized shared)
                {
                    super("ConsumeInteger");
                    sharedObject = shared;
                }
    
            public void run()
                {
                    int value = 0, sum = 0;
    
                    do
                        {
                            try
                                {
                                    Thread.sleep((int) (Math.random() * 3000));
                                }
                            catch(InterruptedException exception)
                                {
                                    System.err.println(exception.toString());
                                }
    
                            value = sharedObject.getSharedInt();
                            sum += value;
                            
                        }while(value != 10);
    
                    System.err.println(getName() + " totale valore ricevuti: " + sum + "\nTermino " + getName());
                }
        }
    
    Classe HoldIntegerSynchronized:
    
    /**
     *
     * @author Luigi
     */
    public class HoldIntegerSynchronized
        {
            private int sharedInt = -1;
            private boolean writeable = true;
    
            public synchronized void setSharedInt( int value )
                {
                    while(!writeable)
                        {
                            try
                                {
                                    wait();
                                }
                            catch(InterruptedException exception)
                                {
                                    exception.printStackTrace();
                                }
                        }
    
                    System.err.println(Thread.currentThread().getName() + " setta intero a " + value);
    
                    sharedInt = value;
    
                    writeable = false;//variabile boolean di controllo
    
                    notify();
                }
    
            public synchronized int getSharedInt()
                {
                    while(writeable)
                        {
                            try
                                {
                                    wait();
                                }
                            catch(InterruptedException exception)
                                {
                                    exception.printStackTrace();
                                }
                        }
    
                    writeable = true;
    
                    notify();
    
                    System.err.println(Thread.currentThread().getName() + " riceve valore intero " + sharedInt);
    
                    return sharedInt;
                }
        }
    
Devi accedere o registrarti per scrivere nel forum
1 risposte