Merkwürdiges Thread-Verhalten

twabuzi

Mitglied
Guten Abend,
mein erweitertes jPanel soll verschiedene Rechtecke zeichnen, die in einer Warteschlange eingefügt und im 50-Millisekunden-Takt abgearbeitet werden. Damit andere Komponenten noch reagieren, wenn Thread.sleep (50) ausgeführt wird, benutze ich mehrere Threads.
Folgender Code ergab sich bisher:
Java:
public void run() {
      System.out.println("Starte Panel-Thread");
      while( true) {
        //BesondereStelle
         try {
            if (stapelToDo.size() > 0){
               System.out.println("Konfiguration wird gezeichnet!");
              
               this.zl_aktuell = this.stapelToDo.get( 0);
               this.stapelToDo.remove( 0);

               repaint();
              
               System.out.println("Verbleibende Konfigurationen: " + this.stapelToDo.size());

               Thread.sleep( 50);
            }
         } catch (InterruptedException ex) {}
      }
   }

Leider funktioniert das Ganze irgendwie nur sehr seltsam und zwar, wenn ich im Code an der Stelle "BesondereStelle" ein System.out.println("") einfüge. Was läuft hier schief?
 
Ein komplettes lauffähiges Beispiel wäre schön.
Handelt es sich bei "stapelToDo" um eine Threadsichere Liste? z.B. "ConcurrentLinkedQueue"?
Wurde "zl_aktuell" als volatile deklariert oder besser noch als "AtomicReference"?
 
Das ganze ergibt doch überhaupt keinen Sinn. Mit einer Schleife mit einem repaint() und einem sleep(50) erreichst du alles aber bestimmt nicht, dass alle 50ms etwas gezeichnet wird.

Warum überhaupt alle 50ms die Queue polllen obwohl du nicht einmal weist ob überhaupt was Neues drin ist? Was wenn in den letzen 50ms zwei Einträge in die Queue eingetragen wurden?

Wie bereits von meinem Vorschreiber angesprochen. Wenn du in dem Thread etwas aus der Queue entfernst, was man eigentlich niemals machen sollte, dann musst du die Queue threadsave machen. Ich glaube kaum das du das gemacht hast...

Sag einfach mal was du genau vorhast und was das Ergebnis sein soll. Da sollte ganz bestimmt ein komplett anderes Konzept her....

Gruß

Claus
 
Guten Morgen. Wie ich bereits geschrieben habe, funktioniert mein Programm so wie ich es mir wünsche, bis auf das eingangs beschriebene Verhalten.
Als Neuling in Bezug auf Threads danke ich dir, DrZoidberg, für die Schlagworte. Das wird mir helfen, mich weiter einzulesen.
 
Ok. Nachdem ich verschiedene Anweisungen in synchronized-Methoden ausgelagert habe (immer dann, wenn eine Variable beschrieben wird) erhalte ich wieder den gleichen Fehler. An der ??-Stelle funktioniert die if-Anweisung nur, wenn ich ein Konsolenausgabe einbaue. Nur dann werden die weiteren Anweisungen ausgeführt. Warum? Hier mein kompletter Code.
Java:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.Vector;

public class SortSearchPanel extends JPanel implements Runnable{
   /*Ein spezielles Panel, das Zahl-Highlight Paare speichert. Dieses kann genutzt
   werden, um Sortier- und Suchalgorithmen zu veranschaulichen.
 
   Verwendung:
   zeichne( int[] tmp_zahlen, boolean[] tmp_highlight )
   Es werden in zwei gleichgroßen Arrays, zum einen die Zahlen, zum anderen die
   Stellen übergeben, an denen die Zahlen hervorgehoben sein sollen.
 
   setIntervall( int millisek)
   Wird die Methode "zeichne" mehrfach hintereinander aufgerufen (z.B. in einer
   Schleife), werden die verschiedenen Übergaben im Abstand einer gewisser Zeit
   gezeichnet. Dieses Intervall kann über setIntervall( int millisek) eingestellt werden.
   */

   private Vector stapelToDo = new Vector();
   private Vector zl_aktuell = new Vector();
 
   private int intervall = 50;
 
   private boolean laufend = false;

   public SortSearchPanel(){    
      Thread t = new Thread(this);
      t.start();
   }

   public void setIntervall( int millisek) {
      this.intervall = millisek;
   }
 
   private synchronized void addKonfiguration( Vector z){
      this.stapelToDo.add( z);
      System.out.println("Neue Konfiguration zum Zeichnen! (Anzahl ingesamt: " + this.stapelToDo.size() + ")");
   }

   public boolean addZahlen( int[] tmp_zahlen, boolean[] tmp_highlight ) {
      if ( tmp_zahlen.length != tmp_highlight.length) {
         return false;
      }
    
      //Übergabe in Zahlenliste zl_tmp einlesen
      Vector zl_tmp = new Vector();
      Zahl tmp_zahl = new Zahl();
    
      for (int i=0; i < tmp_zahlen.length; i++){
         tmp_zahl = new Zahl();
         tmp_zahl.wert = tmp_zahlen[i];
         tmp_zahl.highlight = tmp_highlight[i];
         zl_tmp.add( tmp_zahl);
      }
    
      addKonfiguration( zl_tmp);
      return true;
   }
 
   private synchronized void ladeAktuell() {
      //Methode, die aus dem ToDo-Stapel der zu zeichnenden Konfigurationen
      //die älteste herausnimmt und in zl_aktuell abspeichert.
    
      if ( this.stapelToDo.size() > 0) {
         this.zl_aktuell = (Vector) this.stapelToDo.get( 0);
         this.stapelToDo.remove( 0);
      }
   }
 
   public void run() {
      System.out.println("Starte Panel-Thread");

      while( true) {
         if ( this.laufend) {
            try {
               if (this.stapelToDo.size()>0 ){
                  System.out.println("Konfiguration wird gezeichnet!");
                
                  this.ladeAktuell();
                  repaint();
                
                  System.out.println("Verbleibende Konfigurationen: " + this.stapelToDo.size());

                  Thread.sleep( this.intervall);
               }
            } catch (InterruptedException ex) {}
       
         //??
         } else {
            System.out.println("laufend steht auf false");
         }
      }
   }
 
   public void start() {
      System.out.println("Zeichenprozess starten");
      this.laufend = true;
   }
 
   public void stop() {
      this.laufend = false;    
   }
 
   private synchronized boolean zeichneKonfiguration( Graphics g, Vector zl_aktuell_tmp, int breite, int hoehe){
      if (breite == 0 || hoehe == 0){
         return false;
      }

      int balkenbreite = breite / zl_aktuell_tmp.size();
    
      for ( int i = 0; i< this.zl_aktuell.size(); i++){
         Zahl z_tmp = (Zahl) zl_aktuell_tmp.get( i);
       
         if ( z_tmp.highlight) {
            g.setColor(Color.red);
         } else {
            g.setColor(Color.black);
         }
       
         g.fillRect(i*balkenbreite, hoehe-1-z_tmp.wert, balkenbreite, z_tmp.wert); 
      }
      return true;
   }
 
   public void paintComponent( Graphics g){ 
      g.setColor(Color.white);
      g.fillRect(0, 0, this.getWidth(), this.getHeight());
    
      if (this.zl_aktuell.size() > 0) {
         //zl_aktuell ist nicht leer - es gibt also etwas zu zeichnen
         if ( !zeichneKonfiguration( g, this.zl_aktuell, this.getWidth(), this.getHeight())){
            System.out.println("Fehler beim Zeichnen");          
         }
      }
   }
}
 
Ich habe da mal ein lauffähiges Beispiel draus gemacht. Und es scheint zu funktionieren. Übrigens weiss ich immer noch nicht was für ein Fehler bei dir auftritt.
Java:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.Vector;
import java.util.Random;

public class SortSearchPanel extends JPanel implements Runnable {
  class Zahl {
    int wert;
    boolean highlight;
  }
 
   private Vector<Vector<Zahl>> stapelToDo = new Vector<>();
   private Vector<Zahl> zl_aktuell = new Vector<>();
   private int intervall = 50;
   private volatile boolean laufend = false;

   public void setIntervall( int millisek) {
      this.intervall = millisek;
   }
   private synchronized void addKonfiguration( Vector<Zahl> z){
      this.stapelToDo.add( z);
      System.out.println("Neue Konfiguration zum Zeichnen! (Anzahl ingesamt: " + this.stapelToDo.size() + ")");
   }

   public boolean addZahlen( int[] tmp_zahlen, boolean[] tmp_highlight ) {
      if ( tmp_zahlen.length != tmp_highlight.length) {
         return false;
      }
     
      Vector<Zahl> zl_tmp = new Vector<>();
      Zahl tmp_zahl = new Zahl();
   
      for (int i=0; i < tmp_zahlen.length; i++){
         tmp_zahl = new Zahl();
         tmp_zahl.wert = tmp_zahlen[i];
         tmp_zahl.highlight = tmp_highlight[i];
         zl_tmp.add( tmp_zahl);
      }
   
      addKonfiguration( zl_tmp);
      return true;
   }
   private synchronized void ladeAktuell() {
      if ( this.stapelToDo.size() > 0) {
         this.zl_aktuell = (Vector<Zahl>) this.stapelToDo.get( 0);
         this.stapelToDo.remove( 0);
      }
   }
   public void run() {
      System.out.println("Starte Panel-Thread");

      while(this.laufend) {
         if (this.stapelToDo.size() > 0) {
            System.out.println("Konfiguration wird gezeichnet!");
         
            this.ladeAktuell();
            repaint();
         
            System.out.println("Verbleibende Konfigurationen: " + this.stapelToDo.size());
         }
        try {
           Thread.sleep( this.intervall);
        } catch (InterruptedException ex) {}
      }
   }
   public void start() {
      System.out.println("Zeichenprozess starten");
      this.laufend = true;
      Thread t = new Thread(this);
      t.start();
   }
   public void stop() {
      this.laufend = false;   
   }
   private synchronized boolean zeichneKonfiguration( Graphics g, Vector<Zahl> zl_aktuell_tmp, int breite, int hoehe){
      if (breite == 0 || hoehe == 0){
         return false;
      }

      int balkenbreite = breite / zl_aktuell_tmp.size();
   
      for ( int i = 0; i< this.zl_aktuell.size(); i++){
         Zahl z_tmp = (Zahl) zl_aktuell_tmp.get( i);
      
         if ( z_tmp.highlight) {
            g.setColor(Color.red);
         } else {
            g.setColor(Color.black);
         }
      
         g.fillRect(i*balkenbreite, hoehe-1-z_tmp.wert, balkenbreite, z_tmp.wert);
      }
      return true;
   }
   public void paintComponent( Graphics g){
      g.setColor(Color.white);
      g.fillRect(0, 0, this.getWidth(), this.getHeight());
   
      if (this.zl_aktuell.size() > 0) {
         if ( !zeichneKonfiguration( g, this.zl_aktuell, this.getWidth(), this.getHeight())){
            System.out.println("Fehler beim Zeichnen");         
         }
      }
   }
  
   public static void main(String[] args) {
     JFrame frame = new JFrame();
     SortSearchPanel panel = new SortSearchPanel();
     frame.add(panel);
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setSize(800, 600);
     frame.setVisible(true);
    
     Random rand = new Random();
    
     for(int i = 0; i < 1000; i++) {
       int[] zahlen = new int[10];
       boolean[] highlights = new boolean[10];
       for(int j = 0; j < zahlen.length; j++) {
         zahlen[j] = rand.nextInt(500);
         highlights[j] = rand.nextBoolean();
       }
       panel.addZahlen(zahlen, highlights);
     }
    
     panel.start();
   }
}
 

Zurück
Oben