PDA

View Full Version : Thread in Java


boysna
02-04-2006, 18:37
Ciao a tutti.
Sonno alle prese per la prima volta con i Thread in Java.

Vi scrivo il mio problema:

File OccupaSedia.java:

import java.lang.InterruptedException;

public class OccupaSedia extends Thread{

public int num_partecipanti;
public int num_sedie;
public int num_sessioni;
public Sedia[] array_sedie;
public String[] array_partecipanti;
public Thread runner;
Object obj="a";
int x = 0;


public OccupaSedia(int a, int b, int c){
num_partecipanti = b;
num_sedie = a;
num_sessioni = c;

//Creazione struttura per sedie e partecipanti
array_sedie = new Sedia[num_sedie];

array_partecipanti = new String[num_partecipanti];

//Riempimento delle suddette strutture
for(int e=1; e<=num_sedie; e++){
String nome_sedia = "sedia" + e;
Sedia sedia = new Sedia(nome_sedia,"libera");
array_sedie[e-1] = sedia;
}

for(int d=1; d<=num_partecipanti; d++){
String nome_partecipante = "persona" + d;
array_partecipanti[d-1] = nome_partecipante;
}
}


public synchronized int getNumPartecipanti(){
return num_partecipanti;
}

public synchronized int getNumSedie(){
return num_sedie;
}

public synchronized int getNumSessioni(){
return num_sessioni;
}

public synchronized void setNumPartecipanti(int n){
num_partecipanti = n;
}

public synchronized void setNumSedie(int n){
num_sedie = n;
}

public synchronized void setNumSessioni(int n){
num_sessioni = n;
}

public synchronized void run(){
System.out.println("a");
try{wait();}
catch(InterruptedException e){System.out.println(array_sedie.length);}
System.out.println(array_sedie.length);
int f = 0;
while(f<array_sedie.length){
if(array_sedie[f].getStato()=="libera"){array_sedie[f].occupaSedia();
System.out.println(array_partecipanti[f]);
array_sedie[f].setNameOccupante(array_partecipanti[f]);
f++;}
else f++;
}
notifyAll();
}




public synchronized void metodo(){
int i = 1;
//Ciclo Sessione
while(i<=num_sessioni){
x = 0;
System.out.println("Sessione: " + i);

//Ciclo creazione Thread
while(x<num_partecipanti){
runner = new OccupaSedia(num_sedie, num_partecipanti, num_sessioni);
runner.start();
x++;
}
obj="vai";
notifyAll();
i++;

//Stampa dei risultati di Sessione
int g=0;
while(g<array_sedie.length){
System.out.println(array_sedie[g].nome);
System.out.println(array_sedie[g].getNameOccupante());
g++;
}
}

}
}

Praticamente il metodo "metodo" ancia n thread che si devono bloccare finchè non arriva la notifica che tutti i thread sono stati creati in modo che eseguano il codice a partire dallo stesso momento.

Ma quando incontrano la wait si blocca e non va avanti...

carmen_79
02-04-2006, 20:59
sono alle prese con lo stesso esercizio...ma sono più in panne di te! per caso sei riuscito a far qualcos'altro?

boysna
02-04-2006, 21:46
Anche tu vittima di Polese?

carmen_79
02-04-2006, 21:59
si, ma c'è da piangere!!!

boysna
02-04-2006, 22:58
C'è da piangere soprattutto se pensi che fare questo esercizio di merda si deve ricorrere al forum...

carmen_79
02-04-2006, 23:40
si, e nonostante tutto cmq quel poco ke ho fatto non è nemmeno funzionante!!! :(

sottovento
03-04-2006, 07:22
Ciao,
ho letto la spiegazione, ed il codice sembra riportare quello che e' stato descritto.

Pertanto, e' normale che i thread si blocchino sulla wait(), e' fatta apposta per quello: resteranno bloccati li' fintanto che qualcuno non li "risveglia" con una notify().

Nel codice ci sono due notifyAll(), candidate a risvegliare i thread: una e' posta nel metodo run(), quindi e' fuori gioco (inizialmente, intendo).

L'altra e' nel metodo "metodo" (Ps se fosse stato scelto un altro nome, magari indicante quello che il metodo deve fare, avreste ottenuto aiuto piu' in fretta).

Ma... chi chiama "metodo"? Il codice e' tutto qui? Non e' ovviamente possibile, questo codice e' solo un pezzettino, giusto?

Una volta eseguita la creazione, questo metodo deve farli partire.
Occorre controllare (eventualmente postare) il programma principale, per verificare questa se "metodo" e' chiamato correttamente.

High Flying
Sottovento

sgru
03-04-2006, 09:52
Ecco la traccia:

Corstuire un programma in linguaggio java che, attraverso l’uso dei thread e della mutua esclusione, realizza il gioco Occupa-Sedia. Il gioco consiste nell’avere un certo numero K di sedie ed un numero N di persone con N>K ed un arbitro. Quando l’arbitro da il via le N persone partono contemporaneamente da una stessa posizione e cercano di occupare una sedia. Dopo ogni sessione del gioco, solo le K persone che sono riuscite a sedersi ricevono un punto.
In pratica, occorre definire una classe Sedia per modellare un oggetto sedia che può trovarsi in due possibili stati: libera o occupata. I metodi di tale classe devono consentire di rilevare lo stato della sedia, di occuparla e di conoscere il nome dell’eventuale occupante. Occorre inoltre definire una classe Occupa-Sedia con attributi per rappresentare il numero di partecipanti, il numero di sedie disponibili ed il numero di sessioni previste per una determinata istanza del gioco. Occorre definire una struttura dati per modellare la sequenza di K sedie disponibili ed una per modellare gli N partecipanti al gioco. Sia le sedie che le persone devono essere identificabili tramite un nome (si può usare anche un sequenziale sedia1, sedia2, …, persona1, persona2,…).

Il metodo main dovrà creare un’istanza del gioco, chiedendo all’utente di fornire in input i parametri della stessa (N, K ed il numero di sessioni) ed avviare il gioco. Il tentativo da parte delle N persone di occupare ciascuno una sedia dovrà essere modellato tramite N Thread e tutti dovranno (in teoria) essere avviati “contemporaneamente” (suggerimento: si potrebbero usare wait e NotifyAll). L’accesso dei thread alla struttura dati che modella la sequenza di sedie dovrà essere gestito in modo mutuamente esclusivo, attraverso l’uso di meccanismi di sincronizzazione.
Il risultato finale dovrà consistere nella stampa dei risultati delle varie sessioni di un’istanza del gioco (indicando da chi è occupata ciascuna sedia) unitamente alla classifica finale con i punteggi riportati da ciascuna persona (numero di volte in cui è riuscito a sedersi).

boysna
03-04-2006, 10:47
Questo è un Thread contro Polese!!!

boysna
03-04-2006, 11:36
import java.lang.InterruptedException;

public class OccupaSedia extends Thread{

public int num_persone;
public int num_sedie;
public int num_sessioni;
public int persona_corrente;
public Sedia[] array_sedie;
public String array_persone[];
public Thread runner;
public Object obj="a";
int x = 0;
int h;



public OccupaSedia(int a, int b, int c,int pcurr){
num_persone = b;
num_sedie = a;
num_sessioni = c;
persona_corrente = pcurr;

//Creazione struttura per sedie e partecipanti
array_sedie = new Sedia[num_sedie];

array_persone = new String[num_persone];

//Riempimento delle suddette strutture
for(int e=1; e<=num_sedie; e++){
String nome_sedia = "sedia" + e;
Sedia sedia = new Sedia(nome_sedia,"libera");
array_sedie[e-1] = sedia;
}

for(int d=1; d<=num_persone; d++){
String nome_persona = "persona" + d;
array_persone[d-1] = nome_persona;
}
}


public synchronized int getNumPersone(){
return num_persone;
}

public synchronized int getNumSedie(){
return num_sedie;
}

public synchronized int getNumSessioni(){
return num_sessioni;
}

public synchronized void setNumPersone(int n){
num_persone = n;
}

public synchronized void setPersonaCorrente(int n){
persona_corrente = n;
}

public synchronized void setNumSedie(int n){
num_sedie = n;
}

public synchronized void setNumSessioni(int n){
num_sessioni = n;
}


public synchronized void run(){
while(obj=="vai"){

try{wait();}
catch(InterruptedException e){} }
int f = 0;
while(f<array_sedie.length){

if(array_sedie[f].getStato()=="libera"){array_sedie[f].occupaSedia();
array_sedie[f].setNameOccupante(array_persone[persona_corrente]);
break;}
else f++;
}
}


public synchronized void metodo(){
int[] punteggi = new int[num_persone];
for(int m=1; m<=num_persone; m++){
punteggi[m-1] = 0;
}

int i = 1;
//Ciclo Sessione
while(i<=num_sessioni){
x = 0;
System.out.println("Risultati della giornata numero " + i);

//Ciclo creazione Threads
while(x<num_persone){
OccupaSedia s = this;
s.setPersonaCorrente(x);
runner = s;
runner.start();
x++;
}

notifyAll();
i++;


//Stampa dei risultati di Sessione
int g=0;
while(g<array_sedie.length){
System.out.println(array_sedie[g].nome + " occupata da " + array_sedie[g].getNameOccupante());
String aa = array_sedie[g].getNameOccupante().substring(array_sedie[g].getNameOccupante().length()-1,array_sedie[g].getNameOccupante().length());
int n = Integer.parseInt(aa);
n--;
punteggi[n]++;
g++;
}
System.out.println("");
}

System.out.println("");
System.out.println("Classifica finale del tredicesimo campionato mondiale del gioco della seggiola:");
while(h<array_persone.length){
System.out.println(array_persone[h] + " " + punteggi[h]);
h++;
}
}


}

Questo è il mio codice.
Questo pezzo:
while(x<num_persone){
OccupaSedia s = this;
s.setPersonaCorrente(x);
runner = s;
runner.start();
x++;
}
dovrebbe lanciare un numero pari a num_persone thread del tipo OccupaSedia.

Il metodo run fa in modo che quando il thread è avviato va in attesa e riprende solo quando sono stati avviati tutti i thread. Grazie alla notifyAll() che c'è dopo il while.
Purtroppo mi lancia IllegalStateException. Qualcuno sa perchè? Dovrebbe essere lanciata perchè il metodo start è invocato su un thread gia avviato, ma non era mia intenzione invocarlo sullo stesso thread bensi su uno diverso.

Nel main viene chiamato metodo(Scusate in nome ma ho il fiato sul collo della consegna alle 15:00 e ho messo il primo nome che mi veniva in mente).

boysna
03-04-2006, 11:39
Ho la certezza ke ogni volta ke entro in run il nomedel thread ke ci entra è "thread-2". Questo vuol dire che sto creando sempre lo stesso thread o è normale?

boysna
03-04-2006, 11:42
Vi do anche la classe Sedia e il main.

Sedia:

public class Sedia {

public String stato;
public String occupante = "";
public String nome;

public Sedia(String n, String s){
nome = n;
stato = s;
}

public synchronized String getStato(){
return stato;
}

public synchronized void occupaSedia(){
stato = "occupata";
}

public synchronized String getNameOccupante(){
return occupante;
}

public synchronized void setNameOccupante(String s){
occupante = s;
}

}

Main:


import java.io.*;
import java.io.IOException;
import javax.swing.JOptionPane;

class test {

public static void main(String[] args) {
Object a="1";

//Inserimento dei dati di gioco:persone,sedie e sessioni
String num_persone = JOptionPane.showInputDialog("Inserisci il numero di persone:");
String num_sedie = JOptionPane.showInputDialog("Inserisci il numero di sedie:");
String num_sessioni = JOptionPane.showInputDialog("Inserisci il numero di sessioni:");

int persone = Integer.parseInt(num_persone);
int sedie = Integer.parseInt(num_sedie);
int sessioni = Integer.parseInt(num_sessioni);
int pers = 0;

//Creazione di una istanza del gioco
OccupaSedia gioco = new OccupaSedia(sedie,persone,sessioni,pers);
gioco.metodo();
}
}

rdefalco
03-04-2006, 12:57
Cavolo vedo che Polese si è divertito ;) speriamo non legga il forum...

boysna
03-04-2006, 13:42
Vedo che la fama di Mister Polese è molto conosciuta...

rdefalco
03-04-2006, 13:47
Mah l'ho avuto solo per LP2 e non posso lamentarmene più di tanto... Però ammetto che la sua capacità di criptare il testo di una traccia fino a renderlo incomprensibile è notevole :D

Mi dispiace di non potervi aiutare nei thread, col Java me la cavo ma non li ho fatti ancora... Ciao a tutti!

sottovento
03-04-2006, 14:39
Ciao,
ho dato un'occhiata veloce veloce al tuo codice: hai un illegal state exception perche' cerchi di lanciare (n volte) lo stesso thread, il quale sta gia' girando. Quindi ti risponde che lo stato non e' quello corretto.
Ci sono anche un paio di cose strane: dichiari un oggetto "obj", il quale dovrebbe essere, secondo le intenzioni che ho evinto dal codice, l'oggetto sul quale effettui le sincronizzazioni e poi non lo valorizzi se non in inizializzazione.
Inoltre il confronto fra stringhe non si fa con == (o meglio, questo operatore ha un altro significato rispetto a quello che volevi fare).


Dopo, se il tempo non e' cosi' tiranno, do un'occhiata in maniera piu' approfondita...

High Flying
Sottovento

sottovento
04-04-2006, 06:53
Ciao,
scusa il ritardo ma sono piuttosto impegnato.
Ho avuto poco tempo di guardare il codice, per cui ho potuto fare delle modifiche parziali.
Secondo me, e' piu' logico introdurre un thread "Persona", che implementa il giocatore. Ho fatto queste modifiche (e pochi test, ad esser sincero).
Spero che questo sia una traccia per completare il lavoro. Mi spiace non poterti dare qualcosa di completo.
Le cose da fare ancora sono:
- Sincronizzazione in terminazione (il thread principale deve andare a leggere la classifica solo quando tutti hanno terminato);
- Rendere la ricerca del posto sincronizzata (il thread non puo' e non deve essere interrotto nel tempo che passa fra il controllo della seggiola vuota e la sua occupazione. E' molto importante! Per fortuna e' semplice da fare...).

Il codice e' il tuo, con qualche piccola modifica ed un sacco di println () per controllo. Ci sono anche dei ritardi, li puoi eliminare quando hai risolto i punti di cui sopra


High Flying
Sottovento


import java.lang.InterruptedException;

class Persona extends Thread
{
private Object objStart;
private Sedia[] array_sedie;
private String name;
private int score;
private boolean done;

public Persona (String name, Object objStart, Sedia[] array_sedie)
{
this.name = name;
this.objStart = objStart;
this.array_sedie = array_sedie;
this.score = 0;
this.done = false;
start ();
}

public void run()
{
if (objStart == null)
{
System.out.println ("Programming error - Start object is null");
System.exit (0);
}

while(!done)
{
try
{
synchronized (objStart)
{
System.out.println (name + " in wait");
objStart.wait();
System.out.println (name + " svegliato");
}
}
catch(InterruptedException e)
{
System.out.println ("Exception in wait: " + e); // Downwind - added this for debug purposes
e.printStackTrace (); // Downwind - added this for debug purposes
}
if (done)
{
System.out.println (name + " FINITO");
return; // we should finish application
}

System.out.println ("Persona " + name + " comincia a correre");
for (int i = 0; i < array_sedie.length; i++)
{
if (array_sedie[i].getStato().equals ("libera"))
{
System.out.println ("Persona " + name + " si prende la seggiola " + i);
array_sedie[i].occupaSedia();
array_sedie[i].setNameOccupante(name);
score++;
System.out.println ("Punteggio corrente: " + score);
break;
}
}
}
}

public void finish ()
{
synchronized (objStart)
{
done = true;
}
}

public String getPlayerName ()
{
return name;
}

public int getScore ()
{
return score;
}
}

public class OccupaSedia
{
public int num_persone;
public int num_sedie;
public int num_sessioni;
public int persona_corrente;
public Sedia[] array_sedie;
public Object objStart;
private Persona[] giocatori;

public OccupaSedia(int a, int b, int c,int pcurr)
{
num_persone = b;
num_sedie = a;
num_sessioni = c;
persona_corrente = pcurr;

//Creazione struttura per sedie e partecipanti
array_sedie = new Sedia[num_sedie];

//Riempimento delle suddette strutture
for(int e = 1; e <= num_sedie; e++)
{
String nome_sedia = "sedia" + e;
Sedia sedia = new Sedia(nome_sedia,"libera");
array_sedie[e-1] = sedia;
}

// Create objects and people
objStart = new String ("vai");

giocatori = new Persona[num_persone];
for (int i = 0; i < num_persone; i++)
giocatori[i] = new Persona ("giocatore" + (i + 1), objStart, array_sedie);
}

public int getNumPersone()
{
return num_persone;
}

public int getNumSedie()
{
return num_sedie;
}

public int getNumSessioni()
{
return num_sessioni;
}

public void setNumPersone(int n)
{
num_persone = n;
}

public void setPersonaCorrente(int n)
{
persona_corrente = n;
}

public void setNumSedie(int n)
{
num_sedie = n;
}

public void setNumSessioni(int n)
{
num_sessioni = n;
}

public synchronized void metodo()
{
// try
// {
// Thread.sleep (1000);
// }
// catch (Exception e) { }
for (int sessione = 0; sessione < num_sessioni; sessione++)
{
// Ripristina le sedie a libere
for (int g = 0; g<array_sedie.length; g++)
array_sedie[g].setStato ("libera");

System.out.println("Risultati della giornata numero " + (sessione+1));

// Downwind - all threads are created. I can wake up them
try
{
synchronized (objStart)
{
objStart.notifyAll();
}
}
catch (Exception e)
{
e.printStackTrace ();
}

try
{
Thread.sleep (1000);
}
catch (Exception e) { }

//Stampa dei risultati di Sessione
for (int g = 0; g<array_sedie.length; g++)
System.out.println(array_sedie[g].getName() + " occupata da " + array_sedie[g].getNameOccupante());
System.out.println();

// Wait a few before next session
try
{
Thread.sleep (3000);
}
catch (Exception e) { }
}


System.out.println("");
System.out.println("Classifica finale del tredicesimo campionato mondiale del gioco della seggiola:");
for (int h = 0; h < giocatori.length; h++)
System.out.println(giocatori[h].getPlayerName() + " = " + giocatori[h].getScore());

try
{
Thread.sleep (3000);
}
catch (Exception e) { }

System.out.println ("Notifico a tutti di fermarsi");
for (int i = 0; i < giocatori.length; i++)
giocatori[i].finish();

synchronized (objStart)
{
objStart.notifyAll ();
}
}
}

boysna
04-04-2006, 09:57
Alcuni miei colleghi l'hanno fatto simile al mio e si trovano. Vorrei cercare di aggiustare il meno possibile il mio codice. Praticamente dove lancio gli n thread dovrei cercare di lanciare thread diversi e non uguali, come posso fare?

Comunque fa niente se rispondi tardi. Fallo quando puoi, io aspetto, ormai giusto o sbagliato l'ho consegnato gia il lavoro.

sottovento
04-04-2006, 11:19
Alcuni miei colleghi l'hanno fatto simile al mio e si trovano. Vorrei cercare di aggiustare il meno possibile il mio codice. Praticamente dove lancio gli n thread dovrei cercare di lanciare thread diversi e non uguali, come posso fare?

Comunque fa niente se rispondi tardi. Fallo quando puoi, io aspetto, ormai giusto o sbagliato l'ho consegnato gia il lavoro.
Ok provero' a darci un'occhiata.
Intanto controlla una cosa: cosi' come fatto, il codice non puo' lanciare i thread che vuoi, ed e' questo il senso dell'eccezione che ti compariva.
In pratica, hai creato un oggetto (il thread), quindi puoi fare un solo start.

High Flying
Sottovento

boysna
04-04-2006, 11:32
Ho capito il senso dell'eccezione.
Quindi, visto che il thread che vado a creare è sempre quello, come creo n thread?

sottovento
04-04-2006, 12:28
Ho capito il senso dell'eccezione.
Quindi, visto che il thread che vado a creare è sempre quello, come creo n thread?

Creando n oggetti di quel tipo. Il problema e' che cosi' facendo avrai n copie di tutte le variabili che invece vuoi condividere (quali sedie, ...).
Dovrai quindi apportare delle modifiche. In alternativa, invece che estendere Thread, potresti implementare Runnable e creare i thread basati sul medesimo oggetto. Non dovresti avere piu' copie, ma non so se questo e' quello che cerchi.

boysna
04-04-2006, 17:54
Creando n oggetti di quel tipo. Il problema e' che cosi' facendo avrai n copie di tutte le variabili che invece vuoi condividere (quali sedie, ...).
Dovrai quindi apportare delle modifiche. In alternativa, invece che estendere Thread, potresti implementare Runnable e creare i thread basati sul medesimo oggetto. Non dovresti avere piu' copie, ma non so se questo e' quello che cerchi.

Implementare Runnable? Ok...

Comunque cosa intendi per "non dovresti avere piu copie"

sottovento
05-04-2006, 06:38
Implementare Runnable? Ok...

Comunque cosa intendi per "non dovresti avere piu copie"

Scusa, ho riletto il messaggio precedente ed hai perfettamente ragione a farmi questa domanda. Intendo dire che se fai la new del thread che hai attualmente implementato, ogni oggetto avra' la propria copia delle sedie e di tutto il resto. E' come se ogni giocatore giocasse in una stanza separata, con le proprie sedie. Non e' esattamente quello che vuoi.
Mi riferivo semplicemente a questo, tutti i giocatori condividono le sedie, altrimenti il gioco non ha senso.
"Non dovresti avere piu copie" era solo riferito a questo. Tutto qui

High Flying
Sottovento

boysna
05-04-2006, 09:34
Infatti è quello che cerco, ma come faccio a creare questi thread che condividono gli oggetti invece di crearsene una copia per loro stessi e, come dici tu, giocare in una stanza separata? Non ci arrivo proprio...

sottovento
05-04-2006, 10:19
Infatti è quello che cerco, ma come faccio a creare questi thread che condividono gli oggetti invece di crearsene una copia per loro stessi e, come dici tu, giocare in una stanza separata? Non ci arrivo proprio...

Li crei una sola volta (per esempio, nel metodo "metodo") e li passi al costruttore, oppure crei i vari metodi di set.

Scusa se non posso aiutarti di piu', sono proprio preso...

High Flying
Sottovento

boysna
05-04-2006, 20:04
http://www.hwupgrade.it/forum/showthread.php?t=1173740

Puoi vedere se sei in gradi di risolvere anche questo problema?

rdefalco
05-04-2006, 20:26
http://www.hwupgrade.it/forum/showthread.php?t=1173740
Puoi vedere se sei in gradi di risolvere anche questo problema?

Provo io a darti una mano, anche se sono più "matricola"... Se risolvo posto di là.

boysna
07-04-2006, 20:40
Non ce la faccio a capire da solo...

rdefalco
08-04-2006, 07:43
Non ce la faccio a capire da solo...

Ma hai letto la mia risposta nell'altro thread?

boysna
08-04-2006, 08:18
Nell'altro thread parlavamo del Timer che ho risolto.

Per quanto riguarda i Thread contemporanei ancora non ho capito come fare.

rdefalco
08-04-2006, 08:22
Nell'altro thread parlavamo del Timer che ho risolto.
Per quanto riguarda i Thread contemporanei ancora non ho capito come fare.

Ho capito proverò un po' anche perché interessa pure me :D però non ho ancora la minima idea di come funzionino i thread... entro oggi pomeriggio studio un po' la situazione e cerco di sistemare il tutto...