2013-07-13 23 views
8

Modifica Questo post riguarda un compito a casa che ho per la scuola che detta mi baso sullo swing per visualizzare i miei thread e le bandiere booleane per il blocco.Multi-Threading non funziona correttamente

La mia applicazione crea un gruppo di oggetti "lavoro" che contengono ciascuno un thread. Ogni lavoro appartiene a una creatura. Una creatura può avere più lavori ma può eseguirne solo 1 in un dato momento.

Il mio thread utilizza 2 flag booleani per indicare se è necessario eseguire "killFlag" e "goFlag". Indica la creatura a cui appartiene come "bersaglio". E ogni obiettivo ha un "bozza" booleana per indicare se è occupato o meno con un altro lavoro.

Questo è il filo ogni lavoro deve essere eseguito:

public void run() { 
    long time = System.currentTimeMillis(); 
    long startTime = time; 
    long stopTime = time + 1000 * (long)(jobTime); 
    double duration = stopTime - time; 



    synchronized (this.target) { 
     while (this.target.isWorking) { 
      status = 'w'; 
      showStatus(); // hmmmmmmmm 
      try { 
       this.target.wait(); 
      } catch (InterruptedException e) { 
      } 
     } 

     this.target.isWorking = true; 
    } 

    while (time < stopTime && !killFlag) { 
     try { 
      TimeUnit.MILLISECONDS.sleep(100); 
     } catch (InterruptedException e) { 
     } 

     if (goFlag) { 
      status = 'p'; 
      showStatus(); 
      time += 100; 
      this.showProgress.setValue((int)(((time - startTime)/duration) * 100)); 
     } else { 
      status = 'r'; 
      showStatus(); 
     } 
    }//End While loop here 

     showProgress.setValue(100); 
     status = 'c'; 
     showStatus(); 
     synchronized (target) { 
      target.isWorking = false; 
      target.notifyAll(); 

    } 
} 

In un primo momento ho pensato che fosse target.notifyAll() perché sta gettando un IllegalMonitorStateException, ma quando io commento fuori il filo sarà oggetti costruirà ma quando osservo nella GUI l'80% di essi viene visualizzato come completo senza alcuna interazione da parte mia e l'altro 20% afferma che la creatura è occupata.

In un primo momento ho pensato che fosse perché ho inserito la bandiera di uccisione troppo presto ma quando l'ho spostato più in basso o rimosso, i sintomi persistono ancora. Sono schierato al momento e non ci sono programmatori qui haha, ogni consiglio che potresti fornire significherebbe il mondo.

Per garantire che fornisco informazioni sufficienti di seguito sono i metodi che utilizzo per interagire con i thread. I metodi seguenti funzionano con un pulsante che cambia in base al fatto che il thread sia in esecuzione o meno.

public void showStatus() { //switch that changes status of button used to start/pause/display status of thread 
    switch (this.status) { 
     case 'r' : 
      startJob.setEnabled(true); 
      startJob.setText ("Run"); 
      break; 
     case 'p' : 
      startJob.setEnabled(true); 
      startJob.setText("Pause"); 
      break; 
     case 'w' : 
      startJob.setEnabled(false); 
      startJob.setText("Working"); 
      break; 
     case 'c' : 
      startJob.setEnabled(false); 
      startJob.setText("Job Complete"); 
      break; 
    } 
} 

private class theHandler implements ActionListener {//Listener for Button mentioned above 
    public void actionPerformed (ActionEvent event) { 
     if (event.getSource() == startJob) { 
      if (goFlag) { 
       goFlag = false; 
      } else { 
       goFlag = true; 
       killFlag = false; 
      } 
     } else if (event.getSource() == stopJob) { 
      if (killFlag) { 
       //do nothing 
      } else { 
       killFlag = true; 
       status = 'r'; 
      } 
     } 
    } 
} 

Questo mi sta uccidendo, ho scavato intorno per risolvere questo per 6 ore.

Modifica

Dopo aver regolato il mio codice in base a commento di MadProgrammer il "target.notifyAll()" è fissa. Ora sembra che tutti i thread appaiano sul display come completi anche se i pulsanti lampeggiano casualmente tra stati per una frazione di secondo.

Modifica

Un sacco di modifiche inseriti in risposta ai commenti

Di seguito è riportato come mi definisco la classe lavoro in cui sono definiti killFlag, goFlag, ecc.

class Job extends Item implements SearchableByName, Runnable { 
int           index; 
String          name; 
int           creature; 
double          jobTime; 
Creature         target; 
boolean          goFlag = false; 
boolean          killFlag = false; 
char          status; 
JButton          startJob; 
JButton          stopJob; 
JProgressBar        showProgress; 
JPanel          p1; 

Di seguito è dove Creature (target) è definito in cui booleano isWorking risiede:

class Creature extends Entity implements SearchableByName, SearchableByType, Runnable { 
int          party; 
int          empathy; 
int          fear; 
int          carryCapacity; 
Float         age; 
Float         height; 
Float         weight; 
boolean         isWorking = false; 

E in risposta ai commenti: ecco un quadro di come io sono la visualizzazione dei fili: enter image description here

+5

Il nuovo codice deve utilizzare le astrazioni di concorrenza di livello superiore. Dovresti definire il tuo progetto in termini di compiti ed esecutori, piuttosto che discussioni. È particolarmente difficile utilizzare wait, notify e notifyAll correttamente. Il modo in cui discuti il ​​modo in cui desideri coordinare i tuoi thread, probabilmente dovresti usare CountDownLatch. I tuoi flag semaforo home dovrebbero essere dichiarati volatili, dato che non stai garantendo che gli aggiornamenti che creerai saranno visibili ad altri thread. – scottb

+5

Mentre c'è un'indicazione della GUI, non c'è identificazione del framework. Se stai usando swing, ti consiglio vivamente di dare un'occhiata a [Concurrency in Swing] (http://docs.oracle.com/javase/tutorial/uiswing/concurrency/) mentre stai violando le regole del singolo thread;) – MadProgrammer

+1

target.notifyAll deve essere eseguito all'interno di un blocco sincronizzato, poiché notifyAll richiede il blocco del monitor per funzionare – MadProgrammer

risposta

2

Poiché alcuni codici mancano ancora, enumererò prima alcune ipotesi; in caso contrario, la mia risposta potrebbe non essere corretta.

  1. Il metodo run() fornito è all'interno della classe Job.
  2. il pulsante "Annulla" si fa riferimento è la stopJobJButton

Se avete intenzione di riutilizzare la stessa Job istanza per il riavvio dopo la prova generale prima, allora il vostro problema di fondo è che il vostro run() il metodo termina. Si dispone di un ciclo while che verifica !killFlag, ma una volta che il ciclo termina (vale a dire una volta annullato il lavoro e killFlag == true), non c'è nulla che possa far tornare all'inizio e attendere lo stato successivo goFlag == true per riavviarlo. (Inoltre, considerare se la clausola stopJob nel metodo actionPerformed() ha bisogno di fare qualcosa con goFlag.)

D'altra parte, se avete intenzione di creare una nuova istanza Job per rappresentare il lavoro riavviato, allora si rifugio' t ha mostrato un codice che lo farebbe.

Sono un po 'vago nella mia diagnosi sopra di proposito, per cercare di aiutarvi a capire le cose da soli - questo è il modo migliore per imparare. :) Se hai bisogno di maggiori dettagli, posso provare a fornirli, solo LMK in un commento.

+0

Grazie mille! Fai davvero luce su quello che devo fare! Ho risolto la maggior parte dei problemi relativi ai pulsanti. Penso che quello che ho intenzione di fare è terminare il thread premendo il pulsante Annulla e avviando il thread con il pulsante Esegui. Sto cercando modi sicuri per farlo ora. Grazie mille ancora non potrei ringraziarti abbastanza! –

Problemi correlati