Newsgroup: it.comp.java
Titolo: Settare un tempo massimo per eseguire l'istanza di una classe

Vorrei poter gestire il rischio che l'istanza di una classe, per un errore 
nei dati che le invio o per un errore del mio programma, crei 
involontariamente un loop infinito, con il risultato di impedire 
l'eleborazione dei dati successivi.
Ho trovato informazioni su come gestire il timeout solo di connessioni (es. 
setConnectTimeout, setSoTimeout), ma non č quello che interessa a me.
Si puň fare in qualche modo? Avevo pensato di usare l'orologio per calcolare 
l'ora corrente (x), ma come posso settare un'eccezione al raggiungimento 
dell'ora x+5 secondi? Si noti bene, SOLO se l'ora x+5 viene raggiunta 
durante la costruzione dell'istanza di una classe specifica, NON nell'intero 
programma; il ciclo principale non deve MAI interrompersi per un timeout.
Allego una porzione di codice per chiarire meglio il problema:
do
 {
  //leggo i parametri necessari
  try
   {
    //setto a 5 secondi il tempo massimo per l'esecuzione della riga 
successiva; come posso fare?
    miaClasse a=new miaClasse(parametri);
   }
  catch miaEccezioneTimeout(e)
   {
    System.out.println("Controlla meglio i dati o il programma; 
l'elaborazione ha richiesto piů di 5 secondi");
   }
  //da qui in poi, non importa il tempo di esecuzione
 }
while (ci_sono_ancora_dati);
//il tempo totale puň essere lungo a piacere, il ciclo non va terminato mai 
dal timeout
//Il timeout deve valere SOLO all'interno di miaClasse, e ripartire da 5 
secondi ogni nuova istanza
//inoltre le eventuali connessioni esistenti NON vanno mai terminate dal 
timeout, solo l'esecuzione delle istruzioni contenute
//nel costruttore di miaclasse vanno eventualmente interrotte.
 

 programma; il ciclo principale non deve MAI interrompersi per un timeout.
Fai implementare alle tue classi l'interfaccia Runnable ed
esegui le loro operazioni in un thread separato, sul quale ti metti
in join per il tempo di timeout, scaduto il quale, se il thread e'
ancora in esecuzione, sollevi l'eccezione e prosegui con la successiva elaborazione.
Qualche riga di codice di esempio, anche se bisognerebbe
mettersi li' a disegnare un po' meglio il tutto...
class MiaClasse implements Runnable
{
   public void run()
   {
      // Qui le operazioni della classe che possono generare anomalie
   }
}
Nel tuo ciclo di esecuzione:
do
{
    // leggo i parametri necessari
    MiaClasse a = new miaClasse(parametri);
    // Creo un thread per la classe e lo avvio
    // (come daemon, cosi' se va in loop non impedisce
    //  lo shutdown della JVM al termine dell'applicazione)
    Thread aThread = new Thread(a);
    aThread.setDaemon(true);
    aThread.start();
    // Mi metto in attesa della terminazione
    // ma aspetto al massimo per il tempo di timeout
    aThread.join(<timeout in millisecondi>);
    if (aThread.isAlive())
    {
       System.out.println("Controlla meglio i dati bla bla bla");
       // Qui bisognerebbe fermare il thread sospetto di essere
       // in loop: peccato che non esista un modo "safe" per
       // farlo a livello della classe Thread, quindi dovrebbe
       // essere MiaClasse ad esporre qualche metodo per
       // interromperne l'esecuzione
    }
}
while (ci_sono_ancora_dati);
Ciao
Roberto

Non so se ho capito il problema, ma senza complicarsi troppo la vita
il costruttore di mia classe:
public MiaClasse() throws MiaEccezione{
	boolean cicloTrue=true;
	int timeout=1000*5;
	long start=System.currentTimeMillis();
	while (cicloTrue){
		//codice
		if (start+timout>System.currentMills())
		 throw new MiaEccezione("Tempo scaduto");
	}
}


No, così non va; la costruzione dell'istanza di miaclasse è piena di metodi 
e cicli, non posso mica inserire throw new MiaEccezione in tutti... 

       System.out.println("Controlla meglio i dati bla bla bla");
Vediamo se ho capito: se il thread dura 1 secondo, aThread.join(5000); 
aspetta solo 1 secondo, mentre se dura 6 secondi, l'attesa è solo di 5. 
Quindi non si aspetta per forza il tempo massimo se il thread funziona 
correttamente. Giusto? Se l'attesa diventasse comunque pari al timeout 
sarebbe un bel guaio... per me significherebbe moltiplicare per 10 il tempo 
di esecuzione.
Per capire se il thread ha terminato correttamente il suo lavoro non viene 
sollevata un'eccezione, ma devo usare "if (aThread.isAlive())". È così?
Mi rimane un altro dubbio: se scrivo "miaClasse a = new 
miaClasse(parametri);" (suppongo che la M maiuscola fosse una svista), la 
JVM non esegue le istruzioni del costruttore di miaClasse nel trend corrente 
perchè seguono le righe "Thread aThread = new Thread(a);", 
"aThread.setDaemon(true);" e "aThread.start();"? Altrimenti, in una logica 
di tipo sequenziale, mi aspetterei che  "aThread.start();" non verrebbe mai 
eseguito se l'istruzione precedente "miaClasse a = new 
miaClasse(parametri);" generasse un loop.
Grazie.
Marco

 miaClasse(parametri);" generasse un loop.
Il costruttore dovrebbe avere *solo* compiti di inizializzazione dell'istanza.
Affinche' la soluzione che ti ho delineato funzioni, occorre che il "lavoro
utile" venga eseguito (o direttamente, o invocando altri metodi) all'interno del
metodo run(), che tu *sei obbligato* a definire, in quanto la tua classe
implementa l'interfaccia Runnable.
Ciao
Roberto

 implementa l'interfaccia Runnable.
Insomma, invece di avere qualcosa tipo (invento, per capirci):
public class miaclasse
 {
   private int intero;
   private String stringa;
//costruttore
  public miaclasse(int i,String s)
   {
    intero=i;
    stringa=s;
//calcoli lunghi lunghi lunghi.....
   }
 }
dovrei invece procedere così:
public class miaclasse implements Runnable
 {
   private int intero;
   private String stringa;
//metodo
  public void run();
   {
//calcoli lunghi lunghi utilizzando le variabili intero e stringa, 
inizializzate dal costruttore
   }
//costruttore
  public miaclasse(int i,String s)
   {
    intero=i;
    stringa=s;
   }
 }
Giusto?
 

 l'eleborazione dei dati successivi.
Cosa significa "l'istanza di una classe"?
Se tu hai una porzione di codice che può entrare in un loop infinito, 
significa che al suo interno avrai un loop: prima di entrare nel loop 
controlli i dati in ingresso e verifichi che non diano luogo ad un 
deadlock sulla base della logica del tuo programma.
Impostare un timeout, nel thread corrente, lo puoi fare mettendo un 
controllo ad ogni ciclo. Tuttavia sia chiaro che IMHO gestire 
l'individuazione di un deadlock tramite timeout la trovo una soluzione 
estremamente sporca.

 Giusto?
Si'
Sottoscrivo anche le considerazioni fatte da Vincent Vega
Ciao
Roberto

 tramite timeout la trovo una soluzione estremamente sporca.
Forse sporca, ma mi permetterebbe di non bloccare applicazioni tipo Servlet, 
Socket e affini a causa di un errore specifico, salvo porvi rimedio appena 
possibile.Vi immaginate, solo per fare un esempio, un sito che diventa "out" 
solo perchè un utente ha fatto una richiesta che, con una probabilità di 
1/100.000, provoca un loop? Che anche gli altri 99.999 utenti non 
riuscirebbero a visualizzare alcunchè. 

 riuscirebbero a visualizzare alcunchè. 
Il sito non andrebbe comunque down per questa ragione, fermo restando 
che se ti ci metti sul serio prima o poi ci riesci a tirarlo giù :)
La soluzione è sicuramente sporca per una serie di ragioni alquanto 
ovvie. Qualsiasi sia il loop in questione, sei perfettamente in grado di 
controllare quali condizioni lo portano ad un loop infinito.
Il problema tuo è che in quel codice non ti ci rinvieni e stai cercando 
una soluzione-accrocchio per (come si suol dire) tagliare la testa al 
toro. Per carità, ognuno fa come crede, ma lasciami consigliare che non 
si fa così, eh... :-)