Problema thread Java

di il
22 risposte

Problema thread Java

Buongiorno. Non ho mai capito come utilizzare i thread in java. Leggendo online trovo più dubbi che risposte. cortesemente qualcuno è disposto ad aiutarmi?.
Di seguito ho trovato un vecchio esercizio che va fatto con l'ausilio dei thread:

/*programma che simuli corsa automobilistica.
ogni auto verrà identificata da un nome e un delay in millisecondi GENERATO IN MANIERA CASUALE.
nel main bisognerà creare un menu di scelta che permetta di scegliere n auto partecipanti e inserire nomi uno alla volta.
per ognuno di essi verrà creato un oggetto auto caratterizzato da nome e delay.
il sistema farà poi partire ogni auto e visualizzerà alla fine il nome del vincitore(colui che ha avuto delay minore)
*/
Questo è il mio codice:
Main:

public class Main {

	
	
	public static void main(String[]args)
	
	
	{
		
		
		
		String vincitore=new String();
		
		int i=0;
		String vet2[]= new String[100];
		int vet[]= new int[100];
		classe[] prova=new classe[100];
		Scanner input=new Scanner(System.in);
		System.out.println("Quante auto devono esserci?");
		int z=input.nextInt();
		
		
		for(i=0;i<z;i++)
		{
		prova[i]=new classe(0,0,0);
		}
		
		
		
		for(i=0;i<z;i++)
		{	
vet[i]=prova[i].sommal();
		}
		
		for(i=0;i<z;i++)
		{	
vet2[i]=prova[i].nome();
		}
		
		
		for(i=0;i<z;i++)
		{	
System.out.println("Tempo:"+vet[i]+"     macchina:"+vet2[i]);

		}
		int al=0;
		for(i=0;i<z;i++)
		{	
		vincitore=prova[0].vincitore(vet2[i], vet[i]);
		al++;
		}
		
		
		System.out.println("il vincitore è:"+vincitore);
		
		
	}
}
Classe:

import java.time.chrono.MinguoChronology;
import java.util.Random;
import java.util.Scanner;

public class classe {
	Scanner input=new Scanner(System.in);
public	int somma=0;
	public int n=0;
	public int n1=0;
	Random random=new Random();
	
	public classe(int somma,int n,int n1)
	
	{
		this.somma=somma;
		
		this.n=n;
		this.n1=n1;
				
		
	}
	public String nome1=new String();
	public String nome()
	{
		
	String nome=new String();
	System.out.println("inserisci il nome della macchina\n");
		nome=input.nextLine();
		return nome;
	}
	
	
	
	
	
	public int sommal()
	{
		n=random.nextInt(10);
		n1=random.nextInt(20);
		somma=n+n1;
		return somma;
		
	}
	int al=0;
	int min=0;

	public String vincitore(String a,int b)
	{
		
		
		if (al==0)
		{
			
			 min=b;
			 nome1=a;
			al++;
			
		}
		if(b<min)
			{
				min=b;
				
				nome1=a;
			
			}
			
			
		
		
		return nome1;

	}
	
	
}
Vorrei capire come ottenere lo stesso risultato utilizzando i thread...

22 Risposte

  • Re: Problema thread Java

    Anonimamente22 ha scritto:


    Vorrei capire come ottenere lo stesso risultato utilizzando i thread...
    Se vuoi che per ciascuna auto ci sia un thread, nel cui run() venga fatto uno sleep di un tot di tempo (casuale, come hai riportato) e poi determinare quale auto arriva prima, si può fare benissimo.
    Ma sarebbe utile avere anche un'altra tua classe es. Traguardo con un metodo es. taglia(). Crei 1 (solo uno!) oggetto Traguardo che sarà condiviso tra tutti i thread. Il primo che invocherà il taglia() avrà "vinto".
    Chiaramente taglia() deve essere un metodo che sfrutta la sincronizzazione: solo un thread per volta deve poterlo eseguire.
  • Re: Problema thread Java

    andbin ha scritto:


    Anonimamente22 ha scritto:


    Vorrei capire come ottenere lo stesso risultato utilizzando i thread...
    Se vuoi che per ciascuna auto ci sia un thread, nel cui run() venga fatto uno sleep di un tot di tempo (casuale, come hai riportato) e poi determinare quale auto arriva prima, si può fare benissimo.
    Ma sarebbe utile avere anche un'altra tua classe es. Traguardo con un metodo es. taglia(). Crei 1 (solo uno!) oggetto Traguardo che sarà condiviso tra tutti i thread. Il primo che invocherà il taglia() avrà "vinto".
    Chiaramente taglia() deve essere un metodo che sfrutta la sincronizzazione: solo un thread per volta deve poterlo eseguire.
    Potresti accennarmi a grandi linee come gestire un thread? ho proprio tabula rasa sull'argomento. so cosa sono, so a cosa servono. Ma non ho idea di come si implementino in java
  • Re: Problema thread Java

    Anonimamente22 ha scritto:


    Ma non ho idea di come si implementino in java
    Definire il lavoro di un thread in realtà è la parte più semplice (è il resto che è più difficile....)

    Ci sono 2 strade:

    1) Si estende la classe java.lang.Thread e si ridefinisce il public void run() con il codice da eseguire.

    2) Si implementa in una classe la interfaccia java.lang.Runnable implementando il public void run() . Poi un oggetto di questa classe lo si passa al costruttore di Thread.

    In entrambi i casi hai un oggetto Thread e per avviare il nuovo "flusso di esecuzione" si invoca il metodo start() .
  • Re: Problema thread Java

    andbin ha scritto:


    Anonimamente22 ha scritto:


    Ma non ho idea di come si implementino in java
    Definire il lavoro di un thread in realtà è la parte più semplice (è il resto che è più difficile....)

    Ci sono 2 strade:

    1) Si estende la classe java.lang.Thread e si ridefinisce il public void run() con il codice da eseguire.

    2) Si implementa in una classe la interfaccia java.lang.Runnable implementando il public void run() . Poi un oggetto di questa classe lo si passa al costruttore di Thread.

    In entrambi i casi hai un oggetto Thread e per avviare il nuovo "flusso di esecuzione" si invoca il metodo start() .
    Seguendo i tuoi consigli ho modificato il codice. Vorrei chiederti cortesemente se effettivamente questo è il modo giusto di utilizzare i thread e poi avrei alcune delucidazioni da chiederti.
    Premetto; mi scuso per la rudimentalità del programma, ma sto ancora in uni fino a stasera quindi ho dovuto abbozzare qualcosa di funzionante nel minor tempo possibile xD
    Main:
    import java.util.Scanner;
    
    public class main {
    
    	public static void main(String args[])
    	{
    		random[] numeroCasuale=new random[10];
    		double numero=0;
    		Scanner input=new Scanner(System.in);
    		String nomeVeicolo=null;
    		classeth []prova =new classeth[10];
    		for(int i=0;i<10;i++)
    		{
    		numeroCasuale[i]=new random();
    	numero=	numeroCasuale[i].geneatore();
    	nomeVeicolo=input.nextLine();
    		prova[i]=new classeth(numero,nomeVeicolo);
    		}
    		for(int i=0;i<10;i++)
    		{
    		prova[i].start();
    		}
    		double vincitore=0;
    		String vincitoreNome=prova[0].nomeVeicolo;
    		vincitore=prova[0].valore;
    		for(int i=0;i<10;i++)
    		{
    		if(prova[i].valore<vincitore)
    		{
    			vincitore=prova[i].valore;
    			vincitoreNome=prova[i].nomeVeicolo;
    		}
    		}
    		System.out.println("\n\nVince....\n\n  "+vincitoreNome+"\ncon un delay di... "+vincitore);
    		
    	}
    }
    

    Classe estesa da thread:
    import java.io.Console;
    
    public class classeth extends Thread{
    public double valore;
    public String nomeVeicolo;
    public classeth(double valore,String nomeVeicolo) {
    	this.valore=valore;
    	this.nomeVeicolo=nomeVeicolo;// TODO Auto-generated constructor stub
    }
    	@Override
    	public void run()
    	{
    		try {
    System.out.println("Macchina"+nomeVeicolo+"\n ha finito con:"+valore);
    Thread.sleep((long) valore);
    		}
    		catch(InterruptedException ex){
    			
    	System.out.println("nn funz");	
    		}
    		}
    		}
    
    Classe random:
    import java.util.Random;
    
    public class random {
    	Random c=new Random();
    	
    public double geneatore()
    {
    	double generato=0;
    	generato=c.nextDouble();
    	
    	
    	return generato;
    }
    	
    }
    L'effettivo output del mio programma:
    
    marco
    luca
    lucia
    batmobie
    uomoragno
    programmatore
    caffettiera
    muratore
    vecchiettosexy
    luchetto // sono ovviamente i vari input 
    
    Macchinamarco
     ha finito con:0.8842940373054184
    Macchinauomoragno
     ha finito con:0.9067631015118065
    Macchinalucia
     ha finito con:0.7405700378778313
    Macchinaluca
     ha finito con:0.8487737637880811
    
    
    Vince....
    
      programmatore
    con un delay di... 0.1900314587742442
    Macchinabatmobie
     ha finito con:0.5324388472597239
    Macchinacaffettiera
     ha finito con:0.7258593993215265
    Macchinamuratore
     ha finito con:0.7270007967546651
    Macchinavecchiettosexy
     ha finito con:0.6390088244333736
    Macchinaprogrammatore
     ha finito con:0.1900314587742442
    Macchinaluchetto
     ha finito con:0.9932118491616956
    
    
    E ora diamo il via alle domande xD. Ovviamente sono thread, lavorano in parallelo, quindi come posso fare a dare la stampa del vincitore soltanto una volta che l'ultimo thread abbia finito di lavorare?

    Concettualmente fatto cosi' è giusto l'esercizio?
  • Re: Problema thread Java

    Anonimamente22 ha scritto:


    Concettualmente fatto cosi' è giusto l'esercizio?
    No, non è affatto corretto.

    Partiamo dalla tua classe random. Non ha granché senso di esistere, per come l'hai fatta non dà alcun "valore aggiunto". Se facesse qualcosa di più es. tirar fuori un valore casuale compreso tra n e m, allora potrebbe avere più senso. In ogni caso, una cosa: ti basta 1 solo oggetto java.util.Random, non uno per ciascun thread.

    C'è poi un'altra cosa che comunque ti è sfuggita (o non l'hai letta): il nextDouble() restituisce un valore compreso tra 0.0 (incluso) e 1.0 (escluso!). Quindi non è MAI esattamente 1. Tu poi fai un cast a long per passarlo a sleep. Siccome il valore è sempre 0.xxxx, il cast tronca i decimali e hai SEMPRE 0. Quindi usato così, non serve a nulla.

    Al Thread.sleep(n) devi passare un valore in millisecondi. Quindi 1000 per fare 1 secondo. Puoi decidere tu un intervallo di valori interi, es. tra 500 (mezzo secondo) a 2000 (due secondi). Ma devi usare opportunamente il java.util.Random per ottenere tu questo intervallo.

    Poi comunque ci sono errori di concetto sui thread.

    Fai un ciclo for per fare tutti gli start:
    		for(int i=0;i<10;i++)
    		{
    		prova[i].start();
    		}
    Attenzione che start() NON fa partire subito il run() di un thread. Mette solo il thread in stato "runnable" (cioè che PUO' essere schedulato) ma poi dipende appunto dallo scheduler dei thread decidere QUANDO avviare il thread. E questo purtroppo è molto aleatorio (dipende pure dal S.O.).

    Detto in altro modo: la parte successiva che è molto veloce (fino a prima dell'ultimo println) potrebbe in teoria (e con tempistiche sfortunate) addirittura essere eseguita PRIMA che tutti i tuoi thread inizino la esecuzione. Quindi scritto così NON ha senso.

    L'avevo detto prima. Se vuoi determinare il primo che "arriva" alla fine, devi avere un metodo che faccia da "barriera", che tutti i thread devono invocare esplicitamente alla loro fine.

    Pensa a quanto appena detto e riscrivi il tutto.
  • Re: Problema thread Java

    andbin ha scritto:


    Anonimamente22 ha scritto:


    Concettualmente fatto cosi' è giusto l'esercizio?

    Partiamo dalla tua classe random. Non ha granché senso di esistere, per come l'hai fatta non dà alcun "valore aggiunto". Se facesse qualcosa di più es. tirar fuori un valore casuale compreso tra n e m, allora potrebbe avere più senso. In ogni caso, una cosa: ti basta 1 solo oggetto java.util.Random, non uno per ciascun thread.
    ho corretto la classe random seguendo le tue indicazioni:
    import java.math.BigDecimal;
    import java.util.*;
    
    import javax.annotation.processing.RoundEnvironment;
    
    public class random {
    	Random c=new Random();
    	
    public int geneatore()
    {
    	int generato=0;
    	generato=c.nextInt(2000)+500;
    
    	return generato;
    }
    	
    }
    E ovviamente ho eliminato il vettore di classe random dal main xD

    andbin ha scritto:



    L'avevo detto prima. Se vuoi determinare il primo che "arriva" alla fine, devi avere un metodo che faccia da "barriera", che tutti i thread devono invocare esplicitamente alla loro fine.

    Pensa a quanto appena detto e riscrivi il tutto.
    Qui mi dovresti dare qualche dritta perchè da solo non ci arrivo;
    Ho pensato anche io di creare un'altra classe con un unico metodo che viene lanciato dal primo thread che finisce le sue azioni.
    Ma dall'idea alla pratica c'è l'abisso di mezzo.
    Creare la classe ok;
    
    
    public class traguardo {
    
    	public String vittoria="victory!!!!";
    	
    	
    	
    	public void primo()
    	{
    		
    	}
    
    	
    }
    
    
    Ma come posso fare il modo che sia valida solo per il primo thread "vincitore" e soprattutto che un solo thread alla volta vi possa entrare?.
    Grazie infinite per l'aiuto
  • Re: Problema thread Java

    Anonimamente22 ha scritto:


    ho corretto la classe random seguendo le tue indicazioni:
    Sì beh, ok. Fa già qualcosa di più. Comunque il range è tra 500 e 2499 (500+1999) inclusi.

    Anonimamente22 ha scritto:


    E ovviamente ho eliminato il vettore di classe random dal main xD
    Sì, nel main basta 1 solo oggetto della tua classe random.

    Anonimamente22 ha scritto:


    Ma come posso fare il modo che sia valida solo per il primo thread "vincitore" e soprattutto che un solo thread alla volta vi possa entrare?.
    Ovviamente nel metodo ci dovranno entrare tutti i thread. Ma solo "uno per volta". Il metodo deve essere "atomico". Per renderlo tale è sufficiente che sia marcato synchronized. E ovviamente, attenzione, tutti i thread dovranno condividere lo stesso medesimo oggetto traguardo (altrimenti non è più vera la mutua-esclusione). Banalmente, lo passi a tutti i tuoi thread.

    Nella classe traguardo puoi tenere un flag es. primo inizialmente a true. Se un thread invoca il metodo e primo è true ... è il primo. E quindi metti poi il flag a false. Così gli altri anche se ci passeranno ... buonanotte.

    Ultima questione: come fa il metodo a sapere quale veicolo sta passando al traguardo? Ci sono due modi, dato che hai esteso Thread. Puoi dare il nome del veicolo al thread (sì un thread ha un name). Ma può essere limitante (a seconda di cosa vorrai fare). In alternativa, passi al metodo l'oggetto della classe che hai chiamato classeth. Ovvero il this all'interno del run.
  • Re: Problema thread Java

    andbin ha scritto:


    Nella classe traguardo puoi tenere un flag es. primo inizialmente a true. Se un thread invoca il metodo e primo è true ... è il primo. E quindi metti poi il flag a false. Così gli altri anche se ci passeranno ... buonanotte.
    Ecco io chiedo ,rischiando di dire una castroneria mega galattica;
    Tu dici di creare un flag all'interno della classe traguardo.
    Ma se io lo facessi, e poi instanziassi la classe traguardo all'interno di quella estesa da thread;
    Ogni volta che un thread entra nel metodo, sì ritrova flag a valore di default . La variabile Flag non è condivisa dalle 10 istanze di thread.
    Quindi la domanda è,come faccio a renderla una variabile condivisa xD?
  • Re: Problema thread Java

    Anonimamente22 ha scritto:


    Quindi la domanda è,come faccio a renderla una variabile condivisa xD?
    Crei l'oggetto traguardo nel main e lo passi a tutti gli oggetti classeth che crei.
  • Re: Problema thread Java

    andbin ha scritto:


    Anonimamente22 ha scritto:


    Quindi la domanda è,come faccio a renderla una variabile condivisa xD?
    Crei l'oggetto traguardo nel main e lo passi a tutti gli oggetti classeth che crei.
    No aspetta non ho ben capito come implementarlo? puoi fornirmi un esempio pratico?
  • Re: Problema thread Java

    Anonimamente22 ha scritto:


    No aspetta non ho ben capito come implementarlo? puoi fornirmi un esempio pratico?
    Alla classe che hai chiamato classeth hai già passato un valore (il delay) e un nome .... gli passi anche l'oggetto traguardo.
  • Re: Problema thread Java

    andbin ha scritto:


    Anonimamente22 ha scritto:


    No aspetta non ho ben capito come implementarlo? puoi fornirmi un esempio pratico?
    Alla classe che hai chiamato classeth hai già passato un valore (il delay) e un nome .... gli passi anche l'oggetto traguardo.
    Non ho idea di come fare xD
  • Re: Problema thread Java

    Anonimamente22 ha scritto:


    Non ho idea di come fare xD
    Hai già scritto:
    public double valore;
    public String nomeVeicolo;
    public classeth(double valore,String nomeVeicolo) {
    	this.valore=valore;
    	this.nomeVeicolo=nomeVeicolo;
    Quale è la difficoltà nel mettere un parametro, un campo e un assegnamento in più per il traguardo?

    Ah, quei campi sarebbe meglio se fossero private (e con almeno il metodo getter pubblico). Se li tieni public, almeno rendili final (non più modificabili)
  • Re: Problema thread Java

    andbin ha scritto:


    Anonimamente22 ha scritto:


    Non ho idea di come fare xD
    Hai già scritto:
    public double valore;
    public String nomeVeicolo;
    public classeth(double valore,String nomeVeicolo) {
    	this.valore=valore;
    	this.nomeVeicolo=nomeVeicolo;
    Quale è la difficoltà nel mettere un parametro, un campo e un assegnamento in più per il traguardo?

    Ah, quei campi sarebbe meglio se fossero private (e con almeno il metodo getter pubblico). Se li tieni public, almeno rendili final (non più modificabili)
    La difficoltà sta nel fatto che se io mettessi un campo flag all'interno di quella classe cosi':
    
    public class classeth extends Thread{
    public int valore;
    public String nomeVeicolo;
    public double flag;
    
    public classeth(int valore,String nomeVeicolo,double flag) {
    	this.valore=valore;
    	this.nomeVeicolo=nomeVeicolo;// TODO Auto-generated constructor stub
    this.flag=flag;
    }
    
    Il campo verrebbe inizializzato per ogni istanza di classe. Ho un vettore d'oggetto.
    Potresti implementarmi tu questo pezzo di codice cosi' che io possa capire?
    per quanto riguarda i campi, li ho messi public di proposito, per poterli tranquillamente utilizzare senza get e set. Consideralo un programma con il solo scopo di capire come lavorare con i thread xD
Devi accedere o registrarti per scrivere nel forum
22 risposte