Sui Thread: non funziona niente

di il
9 risposte

Sui Thread: non funziona niente

Ciao.
mi sto studiando i thread e sicuramente ho molto ancora da studiare visto che l'esercizio che mi sono inventato non funziona per niente
Volevo simulare l'atterraggio di più aerei su una unica pista
quindi ho una classe Pista, una Classe Aereo extends Thread.
- prima di atterrare rimane in volo per max 2 secondi
- poi atterra e prende uso della pista

i metodi sono sincronizzati quindi mi aspettavo una cosa sequenziale, invece ho lo stesso risultato di quando non erano impostatoi come sincronizzati:

class Pista {
	private String inUso="LIBERA";
	public synchronized void atterra() {
		inUso = "IN USO";
	}
	public synchronized void libera() {
		inUso = "LIBERA";
	}
	public String uso() {
		return inUso;
	}
}

class Aereo extends Thread{
	Pista p;
	public Aereo(Pista p) {
		this.p=p;
	}
	private void simulaVolo(){ // DA ZERO A 2 SECONDI
		try {
			sleep((int)((Math.random()+1)*2000));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	public void run() {
		simulaVolo(); //RIMANE IN VOLO PER MAX 2 SECONDI
		if (p.uso().equals("IN USO")) 
			System.out.println(Thread.currentThread().getName() + "-------------LA PISTA E' GIA' IN USO");
		p.atterra();  //POI ATTERRA - METTE "IN USO" LA PISTA
		System.out.println(Thread.currentThread().getName() + " pista: " + p.uso());
		try {
			sleep(1000);    // TEMPO PER ATTERRARE 1 SECONDO PER OGNI VELIVOLO 
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		p.libera(); // LIBERA LA PISTA
		System.out.println(Thread.currentThread().getName() + " pista: " + p.uso());
	}
}

public class Aeroporto{
	public static void main(String args[]) {
		Pista p = new Pista();
		for (int i=0;i<3;i++) {   //HO 3 AEREI CHE ASPETTANO DI ATTERRARE
			new Aereo(p).start();
		}
	}
}
ho sempre lo stesso risultato...tranne la sequenza dei Thread che cambia grazie al random

Thread-1 pista: IN USO
Thread-0-------------LA PISTA E' GIA' IN USO
Thread-0 pista: IN USO
Thread-2-------------LA PISTA E' GIA' IN USO
Thread-2 pista: IN USO
Thread-1 pista: LIBERA
Thread-0 pista: LIBERA
Thread-2 pista: LIBERA
Cosa sbaglio? pensavo che synchronized, sincronizzava i thread ma o lo uso male o ho cbagliato qualche classe....
mi aspettavo un

Thread-1 pista: IN USO
Thread-1 pista: LIBERA
Thread-0 pista: IN USO
Thread-0 pista: LIBERA
Thread-2 pista: IN USO
Thread-2 pista: LIBERA
Grazie
Tagan

9 Risposte

  • Re: Sui Thread: non funziona niente

    tagan ha scritto:


    i metodi sono sincronizzati quindi mi aspettavo una cosa sequenziale, invece ho lo stesso risultato di quando non erano impostatoi come sincronizzati:
    Evidentemente non hai ancora chiari i concetti sul multi-threading.

    Tu ti aspetti che se un thread-aereo fa un p.atterra(); allora "qualcosa" resti impegnato in modo che nessun altro thread possa ottenere l'atterraggio fino a quando quel thread iniziale fa un p.libera();

    NON è così che funziona il tuo codice e neanche in generale l'uso di synchronized !!

    Il synchronized su un metodo "di istanza" fa solo acquisire il lock intrinseco dell'oggetto, che può essere acquisito da un solo thread per volta. Ma terminato il metodo il lock viene rilasciato.

    Devi studiare di più ..
  • Re: Sui Thread: non funziona niente

    Sotto la correzione di andbin:

    Come diceva andbin, synchronized fa solo in modo che un thread che entra in un metodo di una risorsa, completi il metodo e altri thread non possono accedere o interferire anche se lo comanda lo scheduler.

    Se lo scheduler interrompe il thread, che sta eseguendo un metodo synchronized, per avviare altri thread eleggibili, quest'ultimi si fermeranno poichè alla richiesta del lock vanno in attesa e non possono far altro che attendere e nessuno lo saprà. Lo scheduler ridarà il controllo anche all'unico thread che nel frattempo ha il lock().

    Quando il thread con il lock esaurisce il metodo ed esce, rilascia anche il lock. Lo scheduler, quando darà il controllo al thread successivo, quest'ultimo riuscirà ad ottenere il lock e quindi passa da uno stato di wait a run ed entra nella risorsa Pista e si ripete la storia.

    Per come l'hai descritto il problema, il thread dovrebbe essere visto come richiesta di atterraggio (azione by metodo run()) nei confronti della risorsa oggetto Pista e richiama il metodo atterraggio().

    In questo caso, il synchronized non è sufficiente poichè serve sia un oggetto lock (per mettersi al riparo da altri istanze Aereo) ma anche un'altro oggetto che rilevi lo stato del lock del metodo atterraggio() e se quest'ultimo è disponibile o meno fare delle attività.

    Pertanto, non bisogna usare synchronized ma la classe Reentrant che è un equivalente di synchronized ma Reentrant consente l'utilizzo delle LockCondition le quali consentono ad un 'iesimo' thread di capire se la risorsa è già usata da un'altro thread e, se si, può fare qualcosa di diverso ogni volta che ha il controllo dallo scheduler fino a quando non si rende disponibile (attesa ciclica await etc).

    Maggiori dettagli sui libri specializzati (es.: thinking for Java 3).

    Saluti
  • Re: Sui Thread: non funziona niente

    cnesan ha scritto:


    Pertanto, non bisogna usare synchronized ma la classe Reentrant che è un equivalente di synchronized ma Reentrant consente l'utilizzo delle LockCondition le quali consentono ad un 'iesimo' thread di capire se la risorsa è già usata da un'altro thread e, se si, può fare qualcosa di diverso ogni volta che ha il controllo dallo scheduler fino a quando non si rende disponibile (attesa ciclica await etc).
    @cnesan: non consigliare cose più "avanti" se @tagan ha già problemi a comprendere bene l'uso di cose più basilari.


    @tagan: usando SOLO synchronized (e nessun altro meccanismo) la gestione corretta dell'atterraggio si PUÒ fare. Ci sono almeno 2 soluzioni che vengono in mente:

    Soluzione 1)
    Fare tutta la gestione dell'atterraggio all'interno di un singolo metodo synchronized, che acquisisce il lock su un oggetto "condiviso" (può essere proprio l'oggetto Pista e il metodo appena detto può benissimo essere in Pista).
    In questo modo l'atterraggio è "atomico" e c'è mutua-esclusione tra thread, due aerei NON possono atterrare contemporaneamente!

    Soluzione 2)
    Usare due metodi in Pista atterra() e libera() MA ATTENZIONE atterra() dovrebbe essere così:

    public synchronized boolean atterra() {

    Restituisce boolean perché la logica dovrebbe essere (inUso variabile di istanza boolean):
    - Se inUso è true, restituisci false (perché appunto già in uso = non può atterrare)
    - Se inUso è false, metti inUso=true e restituisci true (=può atterrare)

    In questo modo il metodo atterra() essendo synchronized è comunque "atomico" e garantisce che NON ci possono essere due thread-aerei che mettono inUso true contemporaneamente.
    Chiaramente chi chiama atterra(), cioè il thread-aereo, riceverà subito un true/false. Se false potrebbe fare uno sleep per poi ripetere dopo il tentativo di atterra(). Insomma, procede con l'atterraggio solo se atterra() dà true.


    Per cose un po' migliori e più corrette nel senso del multi-threading, ad esempio fare proprio andare in "sospensione" il thread finché non si libera la pista, è necessario appunto sfruttare altri meccanismi, come la condition-queue intrinseca degli oggetti (i wait()/notify() degli oggetti) oppure altro di più alto livello.
  • Re: Sui Thread: non funziona niente

    La mia era solo una spiegazione di cosa c'è dietro al synnchronized, perchè ho notato che nel post originale (in generale) un senso di confusione sul significato synchronized.
    In effetti credo che si dovrebbe studiare partendo prima con oggetti più vecchi e passare man mano a quelli più nuovi per due motivi:
    1) Meccanica di funzionamento dei thread e relative soluzioni.
    2) Pro e contro (e limiti) di ogni soluzione adottata.
    -> Lock-wait-notify-notifyAll (Object) -> synchronized -> rentrant() (class) -> Condition -> queue -> etc.

    Infatti alla fine del post consigliavo di documentarsi con libri che spiegano solo quell'argomento. Con istruzioni tipo for while if e etc ci si può buttare in avanti o come si vuole, ma con strutture complesse come i thread bisogna andare a passo lento per non avere lacune. Per evitare conseguenze anche gravi (deadRace e altro) che sono quelle cose che fanno impazzire.

    Ritornando all'esempio: Si utilizza un confronto "IN USO" e poi viene richiamato un'altro metodo come conseguenza. Tra le due chiamate possono essere chiamati tanti altri thread che possono cambiare lo stato dell'istanza Pista (RaceCondition). Ma sapendo che synchronized si limita a "rendere atomico" solo il metodo in cui è dichiarato, si comprende che tra due chiamate dello stesso thread possono essere eseguiti altri thread che possono modificare lo stato della risorsa pista.

    Con comandi standard (While/For/If/etc) il test è facile poichè o funziona oppure no. Nel Multithreading si può avere che per 100 volte va bene (e quindi uno crede di aver risolto il problema) e poi si scopre che ogni tanto si hanno valori sbagliati.

    Saluti a tutti.
  • Re: Sui Thread: non funziona niente

    cnesan ha scritto:


    La mia era solo una spiegazione di cosa c'è dietro al synnchronized, perchè ho notato che nel post originale (in generale) un senso di confusione sul significato synchronized.
    Nessun problema, non era una critica a te o al tuo post .... era solo per non "suggerire" più carne al fuoco per @tagan.
  • Re: Sui Thread: non funziona niente

    Greazie a tutti per i consigli.
    in effetti, ho abbandonato per il momento i thread e ci ritornerò su in un altro momento con più calma e concentrazione.
    Ho visto alcuni esempi sul web anche su html . it e comunque è stato difficile capirlo e neanche sono sicuro di aver capito tutto.

    Quando sarà il momento, userò i vostri consigli per capire da dove iniziare e come finire, come consigliava cnesan
    1) Meccanica di funzionamento dei thread e relative soluzioni.
    2) Pro e contro (e limiti) di ogni soluzione adottata.
    -> Lock-wait-notify-notifyAll (Object) -> synchronized -> rentrant() (class) -> Condition -> queue -> etc.

    Per il momento sto studiamno bene il jdbc e il JavaFX, la libreria java.util e java.lang per padroneggiare al meglio i metodi più usati e come creare un applicativo (semplice, molto semplice) che li utilizza tutti.

    A tal proposito vi chiederò un consiglio, anzi un'idea.

    Grazie.
    Tagan
  • Re: Sui Thread: non funziona niente

    tagan ha scritto:


    Per il momento sto studiamno bene il jdbc e il JavaFX, la libreria java.util e java.lang per padroneggiare al meglio i metodi più usati e come creare un applicativo (semplice, molto semplice) che li utilizza tutti.
    Prima di arrivare a JDBC/JavaFX ti servirebbe avere una idea molto ben chiara di:
    - tutte le principali feature portate da Java 5 (autoboxing/unboxing, enum, generics, annotation ...)
    - tutte le principali collection (almeno quelle in java.util, escludiamo per ora quelle "concurrent")
    - i concetti su Comparable / Comparator
    - il I/O base ( java.io )
    - magari qualcosa anche del networking, anche "base" ( java.net )

    Se poi mi viene in mente altro .. aggiungo ...
  • Re: Sui Thread: non funziona niente

    Concordo
  • Re: Sui Thread: non funziona niente

    andbin ha scritto:


    tagan ha scritto:


    Per il momento sto studiamno bene il jdbc e il JavaFX, la libreria java.util e java.lang per padroneggiare al meglio i metodi più usati e come creare un applicativo (semplice, molto semplice) che li utilizza tutti.
    Prima di arrivare a JDBC/JavaFX ti servirebbe avere una idea molto ben chiara di:
    - tutte le principali feature portate da Java 5 (autoboxing/unboxing, enum, generics, annotation ...)
    - tutte le principali collection (almeno quelle in java.util, escludiamo per ora quelle "concurrent")
    - i concetti su Comparable / Comparator
    - il I/O base ( java.io )
    - magari qualcosa anche del networking, anche "base" ( java.net )

    Se poi mi viene in mente altro .. aggiungo ...
    - tutte le principali feature portate da Java 5 (autoboxing/unboxing, enum, generics, annotation ...) .....OK Gia studiato e nessun problrema ...(le annotazioni...diciamo capito all'85% ??? ...magari le rivedo)
    - tutte le principali collection (almeno quelle in java.util, escludiamo per ora quelle "concurrent") .....OK Gia studiato e nessun problrema
    - i concetti su Comparable / Comparator .....OK Gia studiato ......ma da rivedere....!
    - il I/O base ( java.io ) .....OK Gia studiato e nessun problrema
    - magari qualcosa anche del networking, anche "base" ( java.net ) .....OK Gia studiato e nessun problema

    aggiungo
    JDBC .....OK Gia studiato e nessun problrema

    JavaFX libreria swing ......assolutamente da rivedere...!
Devi accedere o registrarti per scrivere nel forum
9 risposte