Concorrenza, fare wait() per ogni oggetto

di Yves il
13 risposte
Salve,
Devo svolgere questa traccia per un compito, ma non ho idea di come farla.

Ho una lista di oggetti di lunghezza n e devo creare una funzione che per ogni oggetto della lista mi crea un thread con lo scopo di fare la wait su quell'oggetto. Ovviamente poi devo fare anche la funzione che mi sveglia tutti gli oggetti, ma quella è più semplice.

Quindi cosa ho pensato: faccio un ciclo for( Object i : lista) cosi prendo l'object i della lista, poi creo un nuovo thread all'interno del ciclo che fa i.wait(). Solo che non procede con tutti gli altri oggetti della lista la mia funzione.

Come potrei fare?

13 Risposte

  • Yves ha scritto:


    Ho una lista di oggetti di lunghezza n e devo creare una funzione che per ogni oggetto della lista mi crea un thread con lo scopo di fare la wait su quell'oggetto. Ovviamente poi devo fare anche la funzione che mi sveglia tutti gli oggetti, ma quella è più semplice.

    Quindi cosa ho pensato: faccio un ciclo for( Object i : lista) cosi prendo l'object i della lista, poi creo un nuovo thread all'interno del ciclo che fa i.wait(). Solo che non procede con tutti gli altri oggetti della lista la mia funzione.
    Per iniziare, è necessario chiarire alcune cose: innanzitutto per poter invocare wait()/notify()/notifyAll() su un oggetto è obbligatorio acquisire prima il monitor ("lock") di quell'oggetto, ovvero, è necessario usare la parola chiave synchronized.

    Il wait() comunque di norma NON lo si fa così direttamente al volo e basta. Il wait() tipicamente si mette in un ciclo (solitamente un while() ) che deve testare la condizione che deve "reggere" affinché il thread vada e resti in sospensione.
    Faccio sempre l'esempio della coda "bloccante" (perché abbastanza chiaro/ovvio), dove se la coda è vuota, il thread che fa un estrai() deve stare in wait. Quindi nel estrai() si farà una cosa tipo:
    while (_condizione_coda_vuota_) {
        wait();
    }
    Ci sono vari motivi, storici e pratici per questo approccio con il while, che non sto ora a descrivere meglio per brevità.
    Quindi il tuo caso d'uso sicuramente non calza molto bene il modo tipico di utilizzo del wait().

    Ma il wait() diretto (cioè senza test/cicli) comunque lo puoi fare, potrebbe non essere un problema. E probabilmente nel tuo caso d'uso può anche funzionare come ti aspetti.

    Comunque, per creare un thread devi estendere Thread o implementare Runnable. In entrambi i casi, farai un costruttore che riceve l'oggetto che poi mantieni come variabile di istanza nel TuoRunnable (o TuoThread, non importa). Quindi nel run() potrai usare l'oggetto.

    Da quanto hai detto, purtroppo non è molto chiaro il problema o dubbio. Se quanto ho detto non ha chiarito, precisa meglio i tuoi dubbi e magari posta anche il codice.
  • Sembra che a parole spiegare questa cosa sia difficile, siccome è una roba un po' astratta, quindi ti metto il mio codice cosi magari si capisce meglio.

    La funzione penso sia giusta, cosa ne pensi/pensate?
    public void waitAll() throws InterruptedException{
    		for (Object iObject : list) {
    			 new Thread(()->{
    				synchronized (iObject) {
    					
    					try {
    						System.out.println("sono thread " + Thread.currentThread().getId() + " e metto in attesa" + iObject);
    						iObject.wait();
    						System.out.println("sono thread " + Thread.currentThread().getId() + " e ho svegliato" + iObject);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    			}).start();
    		}
    	}
    	
  • Yves ha scritto:


    La funzione penso sia giusta, cosa ne pensi/pensate?
    Hai fatte le cose molto "compattate", cioè definendo il Runnable con una lambda expression e usando direttamente iObject del foreach che quindi diventa una variabile effectively final. E poi facendo lo start "al volo" sul Thread appena creato.

    È più compatto di quello che avevo suggerito io (non potevo certo sapere se conoscevi lambda expression o no) ma comunque il codice, ad occhio, è tecnicamente corretto e fa ciò che avevi indicato nel post di inizio.
    Quindi ci sono dubbi o problemi a riguardo?
  • Grazie della risposta, avrei un'ultimo dubbio.

    Se volessi creare una funzione che fa la notify su tutti gli oggetti della lista, dovrei fare la stessa cosa della waitAll, cioè creare 1 thread e anzichè fare wait() su quellpoggetto faccio notify?
  • Yves ha scritto:


    Se volessi creare una funzione che fa la notify su tutti gli oggetti della lista, dovrei fare la stessa cosa della waitAll, cioè creare 1 thread e anzichè fare wait() su quellpoggetto faccio notify?
    No, basta un banale ciclo facendo per ciascun oggetto il notify() (acquisendo naturalmente il lock prima).
  • Però prima di far partire il ciclo sarebbe meglio fare una thread.sleep(1000) per far si che il thread waker non parta prima che un'altro thread faccia la wait no?
  • public void wakeAll() throws InterruptedException {
    		for (Object iObject : list) {
    			synchronized (iObject) {
    				Thread.sleep(1000);
    				System.out.println("sto per svegliare " + iObject);
    				iObject.notify();
    				
    			}
    			
    		}
    	}
    Un qualcosa del genere dovrebbe funzionare!
  • Yves ha scritto:


    Però prima di far partire il ciclo sarebbe meglio fare una thread.sleep(1000) per far si che il thread waker non parta prima che un'altro thread faccia la wait no?
    Sì certo (ovviamente), ed è anche utile per vedere bene la differenza tra le due stampe, prima e dopo il wait() che hai fatto.

    Yves ha scritto:


    public void wakeAll() throws InterruptedException {
    		for (Object iObject : list) {
    			synchronized (iObject) {
    				Thread.sleep(1000);
    				System.out.println("sto per svegliare " + iObject);
    				iObject.notify();
    			}
    		}
    	}
    Tecnicamente sì ma lo sleep ha senso che sia uno solo prima di tutti i notify. Non uno sleep per ciascuna notify!
    A meno che vuoi veramente vedere che ciascuno si "sveglia" a distanza di 1 sec. Dipende da cosa vuoi "vedere" in output.
  • Va bene, sei stato gentilissimo, non come quelli di stack overflow, ai quali ho fatto la stessa domanda e non mi hanno neanche risposto!

    Posso fare altre domande in merito alla concorrenza in java prossimamente?
  • Yves ha scritto:


    Posso fare altre domande in merito alla concorrenza in java prossimamente?
    Certo! (e io sono tra quelli che la concorrenza in Java la conosce benissimo ...)
  • Wow quanto ti invidio.
    Poi è un'argomento pure interessantissimo!
    Vorrei conoscerla anche io, almeno per passare l'esame ahah

    PS: hai qualche giuda da consigliarmi?
  • Yves ha scritto:


    PS: hai qualche giuda da consigliarmi?
    Guarda ... puoi vedere i libri su cui ho studiato io nella pagina about del mio (nuovo) sito in firma.
  • Perfetto, grazie mille!
Devi accedere o registrarti per scrivere nel forum
13 risposte