Controllo thread

di il
50 risposte

Controllo thread

Buonsalve a tutti.
vi sono mancato lo so!
avrei un dubbio. ci è stata proposta un'esercitazione scolastica dove sostanzialmente abbiamo una miniera che può avere massimo 3 minatori (i thread) attivi. ho provato a risolvere la cosa in questo modo, ma ancora non mi convince. avreste consigli?

for(int i = 0; i < 3; i++)
                {
                    if(threadArray[i] == null)
                    {
                        threadArray[i] = new Thread(new Miner(socket));
                        threadArray[i].start();
                        i = 3;
                    }
                    else
                    {  
                        if(threadArray[i].getState().equals("WAITING"))
                        {
                            threadArray[i].interrupt();
                            threadArray[i] = new Thread(new Miner(socket));
                            threadArray[i].start();
                            i = 3;
                        }
                        else if (i == 3)
                        {
                            PrintWriter writer = new PrintWriter(socket.getOutputStream());
                            writer.println("WAIT");
                        }
                    }       
                }
giustamente se non scrivo bene le cose non mi si capisce bene...
il testo sarebbe tipo così: la miniera si mette in ascolto (server), appena riceve una richiesta dal fabbro (client), passa la richiesta al minatore (thread), e se la richiesta è GET;n, allora il minatore estrarrà materiale. una volta finito di estrarre, deve chiudersi. la miniera può avere al massimo 3 minatori attivi, per cui ho pensato che potevo fare un array di thread e controllare, 1) se lo slot è vuoto, 2) se il thread è operativo, o meno, e quindi chiuderlo. solo che non mi convince molto questa soluzione.

50 Risposte

  • Re: Controllo thread

    KuroKami69 ha scritto:


    il testo sarebbe tipo così: la miniera si mette in ascolto (server), appena riceve una richiesta dal fabbro (client), passa la richiesta al minatore (thread), e se la richiesta è GET;n, allora il minatore estrarrà materiale. una volta finito di estrarre, deve chiudersi. la miniera può avere al massimo 3 minatori attivi, per cui ho pensato che potevo fare un array di thread e controllare, 1) se lo slot è vuoto, 2) se il thread è operativo, o meno, e quindi chiuderlo. solo che non mi convince molto questa soluzione.
    Non è chiarissimo il contesto generale ma perlomeno si capisce che ci sono di mezzo i socket.

    Ma a parte questo, quello che hai scritto e hai postato non va affatto bene. Non è affatto buono concettualmente e tra l'altro dal punto di vista "tecnico" è pure sbagliato: getState() restituisce il valore di una enum ... non un String. Quindi quel equals("WAITING") è totalmente fuori senso.

    Se vuoi gestire un "pool" di max 3 thread, con la possibilità di riutilizzarli per più "lavori", si può fare. Ma NON in quel modo. Se passi al Thread direttamente quel Miner (che presumo sia un Runnable ed è tra l'altro il "lavoro" finale), quando il suo run() termina, il Thread va in stato "dead" e quindi NON lo puoi riutilizzare.
    Per poter riutilizzare il thread dovresti passargli un tuo Runnable speciale (che solo il pool conosce) in modo che esegue un altro run() e quindi "sa" quando termina, per poter fare quindi altro ripetutamente. Serve una architettura un po' più "furba".

    E parti con il fare una classe a sé stante solo per il pool dei thread.


    P.S. presumo che l'uso di un thread-pool come quelli disponibili nel framework da Java 5 non sia accettabile per l' "esercizio".
  • Re: Controllo thread

    Ok per me hai parlato arabo ahahahaha
    i thread li abbiamo appena accennati, non li abbiamo fatti approfonditamente.
    l'esercizio prevede:
    una miniera (il server) che farà:
    1. Si mette in attesa di una richiesta da parte di un fabbro (porta 41000);
    2. Quando riceve la richiesta la passa ad un minatore che possa gestirla.
    3. Torna in attesa di una nuova richiesta.

    un minatore (il thread, quindi implementa runnable) che farà:
    1. Quando la miniera lo fa partire verifica che la richiesta sia di estrarre del materiale (messaggio “GET”), altrimenti si spegne.
    2. Se il messaggio è un “GET” calcola una quantità random di materiale che può estrarre (tra 1 e 5)
    3. aspetta un numero di secondi pari al materiale che deve estrarre
    4. comunica al fabbro un messaggio nella forma “PUT;x” dove x è la quantità di materiale estratto
    5. si spegne

    e infine un fabbro (il client) che farà:
    1. Apre la comunicazione con la miniera (Socket)
    2. Invia una richiesta di estrazione (messaggio nella forma “GET”)
    3. Attende un messaggio contenente la quantità di materiale estratto (“PUT;x”)
    4. Visualizza la quantità di materiale ricevuta

    per finire ci sono 2 versioni avanzate:
    • Miniera: ha a sua disposizione solo tre minatori. Se sono tutti impegnati invia al fabbro un messaggio “WAIT”
    • Fabbro: se riceve un messaggio “WAIT” al posto del “PUT:x” aspetta un tempo casuale tra 1 e 5 secondi e poi ritenta la richiesta,

    e ancora
    Fabbro: chiede materiale fino a raggiungere una quantità fissata

    detto questo, io non so fare nulla se non creare un thread, grossomodo ho capito cosa sono, ma non li so gestire. se ho capito bene getState() restituisce uno state sottoforma di enum no?
    ma sostanzialmente quando un thread (miner) finisce di fare quanto deve, deve morire, quindi mi va bene vada in dead, per poi venire cancellato. quantomeno la versione per dilettanti prevederebbe questo. l'esercizio dice che la miniera ha a disposizione solo 3 minatori, quindi dovrei riutilizzare quelli creati. quindi potrei ragionare in maniera differente. creo una pool per gestirli e li metto già dentro. poi con i controlli vedo il loro stato e decido cosa fare. mi piacerebbe intraprendere questa strada, ma non credo di essere in grado onestamente
  • Re: Controllo thread

    KuroKami69 ha scritto:


    se ho capito bene getState() restituisce uno state sottoforma di enum no?
    Sì. Quando hai dubbi di questo tipo, c'è una soluzione molto semplice: aprire la documentazione "javadoc" del framework per documentarsi.

    KuroKami69 ha scritto:


    quando un thread (miner) finisce di fare quanto deve, deve morire, quindi mi va bene vada in dead, per poi venire cancellato. quantomeno la versione per dilettanti prevederebbe questo. l'esercizio dice che la miniera ha a disposizione solo 3 minatori, quindi dovrei riutilizzare quelli creati.
    Chiariamo una questione: cosa vuoi riutilizzare? Il java.lang.Thread (detto meglio: QUEL tal flusso di esecuzione)? O il Miner (che è solo il lavoro come Runnable)?
    Il Miner non credo che puoi riutilizzarlo. O perlomeno, in teoria sì. Il punto è che per come ho visto nel tuo codice, tu passi il socket al costruttore del Miner. Quindi una istanza del Miner è "legata" a quella tal comunicazione verso il client con quello specifico socket.

    Gli scenari sono principalmente due:

    1) Ti va bene che un thread "muoia" dopo aver eseguito un singolo Miner. Quando il run() del Miner termina, il thread va in stato TERMINATED. A questo punto il java.lang.Thread NON lo puoi riutilizzare. Ne devi creare uno nuovo!

    Quindi nel tuo array "pool", per ciascun elemento: se è null oppure se non-null E terminated, allora puoi creare un nuovo Thread da assegnare in quello slot dell'array. Se non è uno di questi due casi, allora c'è un Thread che sta eseguendo un lavoro, e non lo devi toccare.
    Questa è la soluzione più semplice e veloce. Ma NON riutilizzi i flussi di esecuzione.

    2) Vuoi riutilizzare un thread ("flusso") di esecuzione per la esecuzione di più Miner (Runnable, detto in generale). In questo caso, NON devi far "morire" subito il thread e non devi quindi testare se terminated.
    In uno scenario del genere, il "lavoro" del thread è un grosso loop in cui la esecuzione del run() del tuo Miner è SOLO una piccola parte del lavoro.
    In sostanza hai un ciclo del genere:

    a) attendi di ricevere un "lavoro" (Runnable)
    b) esegui il run() del Runnable
    c) ripeti da a)

    Ci sarebbero da considerare svariate cose:
    - come attendere la ricezione di un lavoro, da parte di un altro thread
    - come gestire le eccezioni se il run() del lavoro dovesse mai lanciare qualcosa
    - come eventualmente gestire lo "shutdown" dei thread.
    Ma sono tutte cose che si fanno, a patto di conoscere dei concetti essenziali sulla sincronizzazione.
  • Re: Controllo thread

    Grazie come sempre per la risposta.
    Allora devo scegliere la prima soluzione perchè per la seconda non so nulla.
    Il confronto tra 2 enum, giá lo avevo fatto a fine 2017... Mi conviene creare quindi una enum e poi confrontarla con lo stato del thread?
  • Re: Controllo thread

    KuroKami69 ha scritto:


    Il confronto tra 2 enum, giá lo avevo fatto a fine 2017... Mi conviene creare quindi una enum e poi confrontarla con lo stato del thread?
    Non c'è da creare alcuna enum. E le enum si possono confrontare per identità di oggetto (reference), oltre ovviamente al equals che fa comunque la cosa "giusta":

    if (unThread.getState() == Thread.State.TERMINATED)
  • Re: Controllo thread

    Ah bella, grazie mille
  • Re: Controllo thread

    Ma il confronto dello state del thread lo butto in un ciclo vero?
  • Re: Controllo thread

    KuroKami69 ha scritto:


    Ma il confronto dello state del thread lo butto in un ciclo vero?
    Hai un array Thread[] (di lunghezza 3). Ciclo for, per ciascun elemento: se null oppure non-null e terminated, puoi creare un nuovo thread. Altrimenti no. E se hai terminato il for senza creare un thread ... hai tutto "occupato".
  • Re: Controllo thread

    Ma se incontro uno alot vuoto poi devo uscire dal ciclo
  • Re: Controllo thread

    KuroKami69 ha scritto:


    Ma se incontro uno alot vuoto poi devo uscire dal ciclo
    Se un elemento dell'array è tale per cui puoi creare un nuovo Thread, sì, il ciclo può terminare lì.
  • Re: Controllo thread

    andbin ha scritto:


    E parti con il fare una classe a sé stante solo per il pool dei thread.
    Ah, come già dicevo, es.:
    public class EsecutoreMaxThread {
        // ....
    
        public EsecutoreMaxThread(int numThread) {
            // ....
        }
    
        public boolean esegui(Runnable r) {
            // ....
        }
    }
    Il esegui ritorna: true = ha trovato uno slot in cui creare un Thread, false = non ha trovato uno slot.
  • Re: Controllo thread

    Per quando l'idea mi alletti, al momento non son in grado di sviluppare il progetto così tanto. Ma dopo che lo consegno e posso prendermela comoda, sicuramente lo migliorerò
  • Re: Controllo thread

    KuroKami69 ha scritto:


    Per quando l'idea mi alletti, al momento non son in grado di sviluppare il progetto così tanto.
    Ma guarda che una classe come quella EsecutoreMaxThread con la logica che ho descritto, pur stringata al minimo, sono 18~22 righe (a seconda dello stile che usi per scriverla)....
  • Re: Controllo thread

    Al momento ho altri problemi ahahahah
    ok stavo cercando di fare la parte di attesa del minatore, quindi gli ho calato un this.wait(n);
    però per funzionare ho dovuto buttarlo dentro un synchronized.
    solo che al momento non funziona ancora. posso avere una rapida spiegazione, in italiano, su come funzionano questi metodi per favore? cioè se io voglio dire al mio minatore "estrai una quantità random" (e questo ok) e ASPETTA n secondi (quantità estratta), quindi estrai di nuovo, fino a raggiungere la quantità richiesta da fabbro. il metodo di estrazione va bene, ma è il wait che mi impalla tutto. come funziona il discorso?
    come non detto, funziona tutto
Devi accedere o registrarti per scrivere nel forum
50 risposte