Thread: IllegalMonitorStateException

di il
28 risposte

28 Risposte - Pagina 2

  • Re: Thread: IllegalMonitorStateException

    andbin ha scritto:


        tipoAcquisti = AttivitaIO.chiediTipoSouvenir();
    
        CreaNuovoScontrino creaScontrino = new CreaNuovoScontrino();
        Executor.perform(creaScontrino);
        scontrinoCorrente = creaScontrino.getRisultato();
    la prima riga permette di visualizzare una finestra dove è possibile scegliere che tipo di souvenir acquistare, mentre le altre righe permettono di creare uno scontrino vuoto per iniziare l'acquisto.
    considera che non tutto il codice l'ho fatto io poichè proviene da una traccia d'esame universitaria che chiedeva appunto di completare dei pezzi di codice.

    andbin ha scritto:


    Ma è proprio quello che ho detto io in generale. Al join il thread di AttivitaPrincipale va in sospensione e si esce dal join solo quando il thread di AttivitaSottoramoMagneti termina.
    ah scusami, avevo inteso male allora.
  • Re: Thread: IllegalMonitorStateException

    newutente ha scritto:


    la prima riga permette di visualizzare una finestra dove è possibile scegliere che tipo di souvenir acquistare
    Ma come? Direttamente nel thread in cui sei? Non sei nel EDT, quindi l'accesso alla UI non è appropriato ... occhio !
  • Re: Thread: IllegalMonitorStateException

    Si quel codice si trova esattamente dentro il metodo run() del thread di AttivitaPrincipale.
    onestamente l'applicazione funziona correttamente ma vorrei capire se ci sono delle imprecisioni nella struttura che a quanto pare ci sono.
    esattamente in cosa quel codice andrebbe cambiato? ripeto, a prescindere dal fatto che l'applicazione funziona vorrei capire BENE se c'è qualcosa che non va strutturalmente parlando.
  • Re: Thread: IllegalMonitorStateException

    newutente ha scritto:


    vorrei capire BENE se c'è qualcosa che non va strutturalmente parlando.
    La regola base sui thread in Swing è semplice: l'accesso alla UI va fatto solo nel contesto del EDT. Da un qualunque altro thread non è appropriato e potrebbe causare problemi.
  • Re: Thread: IllegalMonitorStateException

    Ho trovato la soluzione di quell'esercizio ed effettivamente l'unica parte differente rispetto al codice fatto da me è nella classe del main dove chiede appunto di creare l'interfaccia grafica.
    io l'ho fatta semplicemente creando un oggetto FinestraPrincipale che poi va a creare l'interfaccia, mentre nella soluzione è fatto così:
    
    Runnable target = new Runnable() {
          @Override
          public void run() {
            new FinestraPrincipale();       
          }
        };
        SwingUtilities.invokeLater(target);
    
    questo immagino sia necessario, o almeno consigliato, per far si che non ci siano problemi con i thread dal momento in cui le classi della libreria Swing non sono thread-safe.
    cioè in poche parole si fa in modo che sia il thread principale a creare l'interfaccia. Dico bene?
  • Re: Thread: IllegalMonitorStateException

    Ho ancora qualche dubbio sull'utilizzo dei thread purtroppo e vorrei chiarirmelo una volta per tutte.
    Sto svolgendo un esercizio dove la traccia richiede di simulare una corsa tra alcuni corridori e non appena il primo arriva al traguardo il giudice (messo in attesa appena l'applicazione viene avviata) si risveglia e annuncia il vincitore.
    Il mio problema però è che viene generata una IllegalMonitorException nel momento in cui cerco di risvegliare il giudice.
    Questo è il codice:
    
    package test;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import javax.swing.JOptionPane;
    import dati.Corridori;
    import dati.Giudice;
    
    public class TestCorridori {
    	public static void main(String[] args) {
    		Corridori corridore = new Corridori();
    		Giudice giudice = new Giudice();
    		String numero = JOptionPane.showInputDialog("inserisci il numero di corridori");
    		int numeroCorridori = Integer.parseInt(numero);
    		Thread thread = new Thread(giudice, "GIUDICE");
    		thread.start();
    		
    		creaCorridori(numeroCorridori, corridore, giudice);
    		
    		try {
    			thread.join();
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		Giudice.stampaClassifica();
    	}	
    	
    	
    	public static void creaCorridori(int numero, Corridori corridore, Giudice giudice) {
    		List<Thread> lista = new ArrayList<Thread>(numero);
    		for(int i=0; i<numero; i++) {
    			String nome = JOptionPane.showInputDialog("inserisci il nome del " + (i+1) + "° corridore");
    			Thread thread = new Thread(corridore,nome);
    			lista.add(thread);
    		}
    		Iterator<Thread> iteratore = lista.iterator();
    		while(iteratore.hasNext()) {
    			iteratore.next().start();
    		}
    	}
    }
    
    
    package dati;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import dati.Corridori;
    
    public class Giudice implements Runnable {
    	private static List<Thread> classifica = new ArrayList<Thread>();
    	private static boolean flag = false;
    	//Corridori corridori = new Corridori();
    	
    	@Override
    	public synchronized void run() {
    		try {
    			this.wait();
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		if(flag == false) {
    			vincitore(Corridori.getThread().getName());
    			flag = true;
    		}
    		Giudice.creaClassifica(Corridori.getThread());   
    	}
    	
    	
    	public static void vincitore(String corridore) {
    		System.out.println(corridore + " ha vinto");
    	}
    	
    		
    	public static void creaClassifica(Thread corridore) {
    		classifica.add(corridore);
    	}
    	
    	
    	public static synchronized void risvegliaGiudice(Giudice giudice) {
    		giudice.notify();
    	}
    	
    	
    	public Giudice getGiudice() {
    		return this;
    	}
    	
    	
    	public static void stampaClassifica() {
    		int i=1;
    		for(Thread thread : classifica) {
    			System.out.println(i + "°: " + thread.getName());
    			i++;
    		}
    	}
    }
    
    
    package dati;
    
    public class Corridori implements Runnable {
    	Giudice giudice = new Giudice();
    	
    	@Override
    	public void run() {
    		for(int i=1; i<=10; i++) {
    			try {
    				Thread.sleep(1000);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			System.out.println(Thread.currentThread().getName() + ": " + (i*10) + "m");
    		}
    		System.out.println(Thread.currentThread().getName() + " arrivato");
    		Giudice.risvegliaGiudice(giudice.getGiudice());
    		Giudice.creaClassifica(Thread.currentThread());
    	}
    	
    	
    	public static Thread getThread() {
    		return Thread.currentThread();
    	}
    }
    
    l'eccezione IllegalMonitorStateException viene generata nel momento in cui invochiamo il metodo wait(), notify() o notifyAll() su un oggetto di cui non abbiamo il lock.
    innanzitutto io ero convinto del fatto che invocando uno di quei metodi all'interno di un blocco sincronizzato automaticamente questo comporterebbe l'acquisizione del lock dell'oggetto che credo avvenga correttamente nel mio codice e precisamente nel metodo risvegliaGiudice().
    Il problema forse deriva dal fatto che l'oggetto sul quale è invocato il metodo notify() non è lo stesso sul quale è invocato il metodo wait() anche se credevo di aver risolto con il metodo getGiudice().
    Mi aiutate a capire dove sbaglio?
  • Re: Thread: IllegalMonitorStateException

    newutente ha scritto:


    Mi aiutate a capire dove sbaglio?
    Rispondo solo ora, non ho avuto tempo prima.

    Innanzitutto le tue classi hanno troppa "roba" static ... poco object-oriented, quindi.

    Comunque la cosa più evidente e lampante: il run() di Giudice acquisisce il lock sulla istanza di Giudice (il metodo è di istanza e synchronized). Mentre risvegliaGiudice acquisisce il lock NON sulla istanza di Giudice ma bensì sull'oggetto java.lang.Class relativo alla classe Giudice (perché il metodo è "di classe", static, e synchronized).

    Quindi già tutto questo non può funzionare ... sono lock differenti!
  • Re: Thread: IllegalMonitorStateException

    Si è vero, effettivamente uno rappresenta il lock dell'oggetto, mentre l'altro quello dell'intera classe.
    Comunque anche rendendo il metodo d'istanza non riesco ugualmente ad acquisire nuovamente il lock dell'oggetto e infatti il thread Giudice non riparte, eppure credo che l'oggetto sul quale è chiamato il wait() sia lo stesso sul quale è chiamato notify() quindi il lock dovrebbe essere il medesimo.
    La parte incriminata della classe Giudice è questa:
    
    @Override
    public synchronized void run() {
    	try {
    		this.wait();
    	} catch (InterruptedException e) {
    		e.printStackTrace();
    	}
    	if(flag == false) {
    		vincitore(classifica.get(0).getName());
    		flag = true;
    	}
    }
    	
    	
    public synchronized void risvegliaGiudice(Giudice giudice) {
    	giudice.notify();
    }
    	
    	
    public Giudice getGiudice() {
    	return this;
    }
    
    essendo il metodo run() sincronizzato dovrebbe essere rilasciato correttamente il lock dell'oggetto (il thread che va in attesa è esattamente quello che invoca il metodo run()), successivamente all'interno della classe Corridori viene invocato il metodo risvegliaGiudice (giudice.risvegliaGiudice(giudice.getGiudice());) che dovrebbe permette di restituire lo stesso oggetto sul quale è chiamato il wait() e quindi sbloccare il Giudice ma purtroppo non accade.
    Io penso che il tutto possa dipendere dal fatto che nella classe Corridori creo una nuova istanza di Giudice per poter invocare il metodo e quindi questo non fa altro che restituire un lock diverso rispetto a quello dell'oggetto che ha invocato il wait().
  • Re: Thread: IllegalMonitorStateException

    newutente ha scritto:


    Io penso che il tutto possa dipendere dal fatto che nella classe Corridori creo una nuova istanza di Giudice per poter invocare il metodo e quindi questo non fa altro che restituire un lock diverso rispetto a quello dell'oggetto che ha invocato il wait().
    Non avevo subito osservato bene tutto il tuo codice ed in effetti .... è abbastanza confuso/contorto su questi aspetti.

    Puoi avere N thread ma di oggetti Runnable per i corridori ne hai 1 solo, lo istanzi all'inizio nel main.
    Corridori ha un suo oggetto Giudice e questo lo passa a risvegliaGiudice (tra l'altro avere in Giudice un getGiudice() che restituisce il this è inutile e poco sensato).

    Il punto è che nel main crei un altro Giudice (che è un altro Runnable) e questo lo usi per il Thread del giudice. Ma è un altro oggetto, diverso dal Giudice che c'è nell'oggetto Corridori.

    Soluzione: rendi il tutto più pulito, lineare e object-oriented.
  • Re: Thread: IllegalMonitorStateException

    Ho ristrutturato un po' il programma, non funziona ancora correttamente perchè il Giudice in realtà non si risveglia però per il momento volevo sapere se in questo modo è più object-oriented:
    
    public class TestCorridori {
    	protected static boolean flag = false;
    	
    	public static boolean getFlag() {
    		return flag;
    	}
    	
    	public static void setFlag(boolean flag) {
    		flag = flag;
    	}
    	
    	public static void main(String[] args) {
    		Corridori corridore = new Corridori();
    		Giudice giudice = new Giudice();
    		String numero = JOptionPane.showInputDialog("inserisci il numero di corridori");
    		int numeroCorridori = Integer.parseInt(numero);
    		Thread thread = new Thread(giudice, "GIUDICE");
    		thread.start();
    		creaCorridori(numeroCorridori, corridore, giudice);
    		while(true) {
    			if(getFlag()==true) {
    				synchronized(thread) {
    					thread.notify();
    				}
    			}
    		}
    	}	
    	
    	public static void creaCorridori(int numero, Corridori corridore, Giudice giudice) {
    		List<Thread> lista = new ArrayList<Thread>(numero);
    		for(int i=0; i<numero; i++) {
    			String nome = JOptionPane.showInputDialog("inserisci il nome del " + (i+1) + "° corridore");
    			Thread thread = new Thread(corridore,nome);
    			lista.add(thread);
    		}
    		Iterator<Thread> iteratore = lista.iterator();
    		while(iteratore.hasNext()) {
    			iteratore.next().start();
    		}
    	}
    }
    
    
    public class Corridori implements Runnable {
    	
    	@Override
    	public void run() {
    		for(int i=1; i<=10; i++) {
    			try {
    				Thread.sleep(1000);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			System.out.println(Thread.currentThread().getName() + ": " + (i*10) + "m");
    		}
    		System.out.println(Thread.currentThread().getName() + " arrivato");
    		Giudice.creaClassifica(Thread.currentThread());
    		TestCorridori.setFlag(true);
    	}
    }
    
    
    public class Giudice implements Runnable {
    	private static List<Thread> classifica = new ArrayList<Thread>();
    	
    	
    	@Override
    	public synchronized void run() {
    		try {
    			wait();
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		vincitore(classifica.get(0).getName());
    		stampaClassifica();
    	}
    	
    	
    	public void vincitore(String corridore) {
    		System.out.println("\n" + corridore + " ha vinto");
    	}
    	
    	
    	public static void creaClassifica(Thread corridore) {
    		classifica.add(corridore);
    	}
    	
    	
    	public void stampaClassifica() {
    		int i=1;
    		for(Thread thread : classifica) {
    			System.out.println(i + "°: " + thread.getName());
    			i++;
    		}
    	}
    }
    
    ho definito molta "roba" static perchè mi serviva nel main(), quindi contesto statico, e inoltre per evitare di dover creare delle istanze per invocare i metodi proprio perchè questo può creare problemi per l'acquisizione dei lock.
  • Re: Thread: IllegalMonitorStateException

    Scusate se posto di nuovo ma non vorrei che il mio post sia finito infondo, voglio capire il problema.
  • Re: Thread: IllegalMonitorStateException

    newutente ha scritto:


    per il momento volevo sapere se in questo modo è più object-oriented
    No, non mi pare particolarmente object-oriented. Un sacco di cose "static", invocazioni di metodi static tra le classi, ecc...

    Vedo di farti un esempio.
  • Re: Thread: IllegalMonitorStateException

    Ecco qui.
    public class TestCorsa100Metri {
        public static void main(String[] args) {
            final int numeroCorridori = 4;
    
            Giudice giudice = new Giudice();
            Thread threadGiudice = new Thread(giudice, "GIUDICE");
            threadGiudice.start();
    
            Corsa corsa = new Corsa(giudice, numeroCorridori, 100);
    
            for (int i = 1; i <= numeroCorridori; i++) {
                Corridore corridore = new Corridore(corsa);
                Thread threadCorridore = new Thread(corridore, "CORRIDORE-" + i);
                threadCorridore.start();
            }
        }
    }
    public class Corridore implements Runnable {
        private Corsa corsa;
    
        public Corridore(Corsa corsa) {
            this.corsa = corsa;
        }
    
        public void run() {
            try {
                corsa.corridorePronto();   // attende partenza appena TUTTI sono pronti
    
                for (int i = 1; i <= corsa.getLunghezzaCorsa(); i++) {
                    Thread.sleep((int) (120 + 100 * Math.random()));
                    System.out.println(Thread.currentThread().getName() + " @ " + i + "m");
                }
    
                corsa.corridoreArrivato();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    import java.util.ArrayList;
    import java.util.List;
    
    public class Corsa {
        private final Object partenza = new Object();
        private final Object arrivo = new Object();
    
        private final Giudice giudice;
        private final int numeroCorridori;
        private final int lunghezzaCorsa;
        private int corridoriPronti;
        private int corridoriArrivati;
        private List<String> classificaCorridori = new ArrayList<String>();
    
        public Corsa(Giudice giudice, int numeroCorridori, int lunghezzaCorsa) {
            this.giudice = giudice;
            this.numeroCorridori = numeroCorridori;
            this.lunghezzaCorsa = lunghezzaCorsa;
        }
    
        public int getLunghezzaCorsa() {
            return lunghezzaCorsa;
        }
    
        public void corridorePronto() throws InterruptedException {
            synchronized (partenza) {
                corridoriPronti++;
    
                if (corridoriPronti < numeroCorridori) {
                    while (corridoriPronti < numeroCorridori) {
                        partenza.wait();
                    }
                } else {
                    partenza.notifyAll();
                }
            }
        }
    
        public void corridoreArrivato() {
            synchronized (arrivo) {
                corridoriArrivati++;
                classificaCorridori.add(Thread.currentThread().getName());
    
                if (corridoriArrivati == numeroCorridori) {
                    giudice.dichiaraFineCorsa(classificaCorridori);
                }
            }
        }
    }
    import java.util.List;
    
    public class Giudice implements Runnable {
        private final Object fineCorsa = new Object();
        private List<String> classificaCorridori;
    
        @Override
        public void run() {
            try {
                System.out.println("Giudice in attesa della fine corsa ...");
    
                synchronized (fineCorsa) {
                    while (classificaCorridori == null) {
                        fineCorsa.wait();
                    }
                }
    
                System.out.println("Corsa terminata!");
                System.out.println("Il giudice dichiara la seguente classifica:");
    
                for (int i = 0; i < classificaCorridori.size(); i++) {
                    System.out.println(i+1 + ") " + classificaCorridori.get(i));
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public void dichiaraFineCorsa(List<String> classificaCorridori) {
            synchronized (fineCorsa) {
                this.classificaCorridori = classificaCorridori;
                fineCorsa.notify();
            }
        }
    }

    P.S. quanti "static" vedi nel mio esempio?
  • Re: Thread: IllegalMonitorStateException

    Ti ringrazio, ora mi è più chiaro.
Devi accedere o registrarti per scrivere nel forum
28 risposte