# Threads nacheinander ausführen



## Joey85 (11. Jun 2014)

Hallo,

ich habe folgendes Problem: Ich baue mir gerade mit Netbeans eine GUI. Ich habe verschiedene Threads die durch einen click auf einen bestimmten button ausgeführt werden.
Bsp.:

privat class a extends Thread {
public void run(){
dosomething;
 }
}

private doActionPerformed(){
a a1 = new a();
a1.start();
}

Jetzt will ich bei einem button aber, dass mehrere threads hintereinander ausgeführt werden. Zur zeit werden alle parallel ausgeführt, was aber nicht sein soll.

private doActionPerformed(){
a a1 = new a();
a1.start();
b b1 = new b();
b1.start();
usw...
}

Wie kriege ich es hin, dass erst gewartet wird bis a ausgeführt wird und dann erst b?


----------



## Joose (11. Jun 2014)

*Java-Code bitte in JAVA-Tags schreiben!*

Verwende die Methode 
	
	
	
	





```
join()
```
 die dir Thread anbietet


----------



## Joey85 (11. Jun 2014)

Das habe ich probiert. Jedoch besteht der Anfang eines Threads bei mir immer aus einem Dialog. Wenn ich join benutze ist das Dialogfenster komplett weiß und ich kann nix machen.


----------



## Joose (11. Jun 2014)

Jap weil sich Thread und GUI-Thread hier in die Quere kommen.
Der GUI-Thread und dein Thread sollten unabhängig von einander laufen!
Stichwort: SwingWorker with Thread


----------



## Joey85 (11. Jun 2014)

Könntest du mir n kurzes Beispiel geben?


----------



## Joose (11. Jun 2014)

Mit meinen Stichwort findest du auf Google Beispiele und Erklärungen wie Sand am Meer.


----------



## Joey85 (12. Jun 2014)

Könnte man nicht auch die threads irgendwie synchronisieren?


----------



## Joose (12. Jun 2014)

Joey85 hat gesagt.:


> Könnte man nicht auch die threads irgendwie synchronisieren?



Was genau willst du nun erreichen? Sollen sie parallel oder seriell laufen?
Was aber auf alle Fälle zu machen wäre -> GUI aus dem Thread raus

Ein simples Code Beispiel was du hast wäre natürlich praktisch


----------



## Joey85 (12. Jun 2014)

OK. Die threads sollen seriell laufen.

```
public class normalization extends Thread {

               public void run() {
            
            File[] file = FileChooser_txt.getSelectedFiles();
            if (file.length == 0) {
                Text1.setText("No file loaded.");
            } else if (file.length == 1) {
                String[] pfad = {file[0].getAbsolutePath().replace("\\", "/")};
                String name = file[0].getName().substring(0, file[0].getName().lastIndexOf(46));
                File normalize = new File(file[0].getParent(), name + "_normalized.txt");
                String[] newfile = {normalize.getAbsolutePath().replace("\\", "/")};

                String[] methods = {"mean", "first", "none"};
                String[] transformation = {"none", "log"};

                JComboBox box1 = new JComboBox(methods);
                JComboBox box2 = new JComboBox(transformation);

                Object[] message = {"Method of normalization: ", box1, "Transformation: ", box2};
                int resp = JOptionPane.showConfirmDialog(null, message, "Parameters of the normalization",
                        JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);

                if (resp == JOptionPane.OK_OPTION) {
                    String method = (String) box1.getSelectedItem();
                    String transform = (String) box2.getSelectedItem();
                    final ProgressMonitor pbar = new ProgressMonitor(monitor, "Normalization...",
                            "Waiting...", 0, 100);
                    monitor.setVisible(true);
                    String[] meth = {method};
                    String[] trans = {transform};
                    
                    if (meth[0] == null || trans[0] == null) {
                        //  Text2.setText("Aborted by user.");
                    } else {
                        double counter = 1.0;
                        .....
                        double percent = (counter / (double) file.length) * 100;
                        pbar.setProgress((int) percent);
                        pbar.setNote("Operation is " + (int) percent + "% complete");
                        if (pbar.isCanceled()) {
                            pbar.close();
                            monitor.setVisible(false);
                            //System.exit(1);
                            return;
                        }
                    }
                    File neu = new File(newfile[0].replace("\\", "/"));
                    if (neu.exists()) {
                        Text2.setText("Normalized values of " + name + " saved at: " + newfile[0].replace  ("\\", "/"));

                    } else {
                        Text2.setText("Error. Normalization failed. Check your input data.");
                    }
                } else {
                    Text2.setText("Normalization aborted by user.");
                }
                monitor.setVisible(false);            
        }
    }


public class something extends Thread {

               public void run() {
            File[] file = FileChooser_txt.getSelectedFiles();
            if (file.length == 0) {
                Text1.setText("No file loaded.");
            } else if (file.length == 1) {
                String[] pfad = {file[0].getAbsolutePath().replace("\\", "/")};
                String name = file[0].getName().substring(0, file[0].getName().lastIndexOf(46));
                File normalize = new File(file[0].getParent(), name + "_normalized.txt");
                String[] newfile = {normalize.getAbsolutePath().replace("\\", "/")};

                String[] methods = {"mean", "first", "none"};
                String[] transformation = {"none", "log"};

                JComboBox box1 = new JComboBox(methods);
                JComboBox box2 = new JComboBox(transformation);
                ......
      }
   }
}


private void Automated1ActionPerformed(java.awt.event.ActionEvent evt) {
                normalization norm = new normalization();
                norm.start();
                try {
                   norm.join();
               } catch (InterruptedException ex) {
                    Logger.getLogger(CyBar2.class.getName()).log(Level.SEVERE, null, ex);
                }

                something some = new something();
                some.start();

                try {

                some.join();
                } catch (InterruptedException ex) {
                    Logger.getLogger(CyBar2.class.getName()).log(Level.SEVERE, null, ex);
               }
}
```

Ich habe gerade probiert den GUI-Teil in der AutomatedActionPerformed-Methode zu lassen und dann die Parameter dem Thread zu übergeben. Wenn ich allerdings norm.start(mit parameter) aufrufe, geht die public void run()-Methode nichtmehr. norm.run(mit parameter) würde gehen, allerdings ist die GUI dann eingefroren.


----------



## Joose (12. Jun 2014)

Joey85 hat gesagt.:


> Ich habe gerade probiert den GUI-Teil in der AutomatedActionPerformed-Methode zu lassen und dann die Parameter dem Thread zu übergeben. Wenn ich allerdings norm.start(mit parameter) aufrufe, geht die public void run()-Methode nichtmehr. norm.run(mit parameter) würde gehen, allerdings ist die GUI dann eingefroren.



Passt, getrennt sollten sie auch sein!
Wie oben schon gesagt 





> Jap weil sich Thread und GUI-Thread hier in die Quere kommen.


lösen nähere Infos dazu findest du hier (Stichworte: Java EDT, SwingWorker, GUI blocked)

Dadurch das du 
	
	
	
	





```
run
```
 direkt aufrufst blockiert dieser solange alle Aktionen die die GUI aktualisieren sollen (auch window resize etc.) daher musst du deinen gewünschten Thread unabhängig vom GUI Thread laufen lassen.


----------



## Joey85 (12. Jun 2014)

Aber warum funktioniert start() nichtmehr, wenn man Parameter übergibt?


----------



## Joose (12. Jun 2014)

```
start()
```
 führt eine vorhandene 
	
	
	
	





```
run()
```
 Methode aus. Da deine aber nun Parameter erwartet, findet 
	
	
	
	





```
start()
```
 nichts zum Ausführen!

Setze deine Parameter über setter Methoden und rufe dann ganz normal 
	
	
	
	





```
start()
```
 auf.
(Und die Parameter der run Methode musst du natürlich wieder entfernen


----------



## Joey85 (17. Jun 2014)

Hab das jetzt per setter und getter Methoden gelöst. Leider bleibt die GUI immernoch hängen.


```
private class  normalization extends Thread {
        String[] pfad;
        String[] newfile;
        String[] meth;
        String[] trans;
        
        public void setpfad(String[] name){
         pfad=name;
     }
        public String[] getpfad(){
         return pfad;
        }
....
}

 private void NormalizeActionPerformed(java.awt.event.ActionEvent evt) {                                          
        // TODO add your handling code here:
        File[] file = FileChooser_txt.getSelectedFiles();

            if (file.length == 0) {
                Text1.setText("No file loaded.");
            } else if (file.length == 1) {
                String[] pfad= {file[0].getAbsolutePath().replace("\\", "/")};
                
                //System.err.println(file[0].getName().lastIndexOf("."));
                String name = file[0].getName().substring(0, file[0].getName().lastIndexOf(46));
                //System.err.println(name);
                File normalize = new File(file[0].getParent(), name + "_normalized.txt");
                String[] newfile= {normalize.getAbsolutePath().replace("\\", "/")};
                System.out.println(newfile[0]);

                String[] methods = {"mean", "first", "none"};
                String[] transformation = {"none", "log"};

                JComboBox box1 = new JComboBox(methods);
                JComboBox box2 = new JComboBox(transformation);

                Object[] message = {"Method of normalization: ", box1, "Transformation: ", box2};
                int resp = JOptionPane.showConfirmDialog(null, message, "Parameters of the normalization",
                        JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);

                if (resp == JOptionPane.OK_OPTION) {
                    String method = (String) box1.getSelectedItem();
                    String transform = (String) box2.getSelectedItem();
                   // final ProgressMonitor pbar = new ProgressMonitor(monitor, "Normalization...",
                    //        "Waiting...", 0, 100);
                   // monitor.setVisible(true);
                    String[] meth = {method};
                    String[] trans= {transform};
                    
                   normalization norm = new normalization();
                   norm.setpfad(pfad);
                   norm.setnew(newfile);
                   norm.settrans(trans);
                   norm.setmeth(meth);
                   norm.start();
                    try {
                        norm.join();
                    } catch (InterruptedException ex) {
                        Logger.getLogger(CyBar2.class.getName()).log(Level.SEVERE, null, ex);
                    }
         
                } 
....
}
}
```


----------



## Joose (17. Jun 2014)

Joey85 hat gesagt.:


> ```
> normalization norm = new normalization();
> norm.setpfad(pfad);
> norm.setnew(newfile);
> ...



1. Klassennamen schreibt man immer groß -> UpperCamelCase

2. Dein Thread blockiert noch immer den GUI Thread (Stichwort EDT Thread). Daher kann deine GUI solange nicht reagieren und etwas machen solange dein Thread rennt.


----------



## Joey85 (17. Jun 2014)

Zu 1. : ja ok, das ändere ich noch.
Zu 2. : Wie kann ich das ändern?

Sorry für die Fragen aber ich bin noch nicht so fit in Java.


----------



## Joose (17. Jun 2014)

Stichwörter die dir bei der Suche helfen können

EDT, invoke Later, Event Dispatcher Thread, SwingWorker, SwingUtilities


----------



## Joey85 (17. Jun 2014)

Ja finden tu ich da viel, verstehen allerdings nicht . Was müsste ich an meinem code noch ändern, damit der thread im Hintergrund ausgeführt wird und nicht die GUI blockiert?


----------



## Joose (17. Jun 2014)

Nein so nicht. Lies dir entsprechende Themen durch, teste mal in einem simplen Beispiel. Solltest du etwas nicht verstehen dann frage danach (inkl Code).
Einfach nach der Lösung fragen sieht hier keiner gerne.


----------



## Joey85 (17. Jun 2014)

OK. Also ist es erstmal richtig, dass ich die Klasse Thread dabei nicht benötige, sondern stattdessen die Klasse SwingWorker? Ich kann einfach nicht unterscheiden, was in den GUI-Teil alles reinkommt und was in den eigentlichen berechnenden thread.

Nachtrag:

Habs jetzt hinbekommen. Habs wiefolgt geändert:

```
class  Normalization extends SwingWorker<Integer,Integer> {
      
        String[] pfad;
        String[] newfile;
        String[] meth;
        String[] trans;
        
        public void setpfad(String[] name){
         pfad=name;
     }
        public String[] getpfad(){
         return pfad;
        }
        
           public void setnew(String[] newpath){
           newfile=newpath;
     }
        public String[] getnew(){
         return newfile;
        }
        
              public void setmeth(String[] method){
         meth=method;
     }
        public String[] getmeth(){
         return meth;
        }
        
           public void settrans(String[] transform){
           trans=transform;
     }
        public String[] gettrans(){
         return trans;
        }
        

          protected Integer doInBackground() throws Exception{
          .....
           return 42;
    }
}

private void NormalizeActionPerformed(java.awt.event.ActionEvent evt) {                                          
        // TODO add your handling code here:
        File[] file = FileChooser_txt.getSelectedFiles();
              System.out.println(file.length);
            if (file.length == 0) {
                Text1.setText("No file loaded.");
            } else if (file.length == 1) {
                String[] pfad= {file[0].getAbsolutePath().replace("\\", "/")};
                
                //System.err.println(file[0].getName().lastIndexOf("."));
                String name = file[0].getName().substring(0, file[0].getName().lastIndexOf(46));
                //System.err.println(name);
                File normalize = new File(file[0].getParent(), name + "_normalized.txt");
                String[] newfile= {normalize.getAbsolutePath().replace("\\", "/")};
                System.out.println(newfile[0]);

                String[] methods = {"mean", "first", "none"};
                String[] transformation = {"none", "log"};

                JComboBox box1 = new JComboBox(methods);
                JComboBox box2 = new JComboBox(transformation);

                Object[] message = {"Method of normalization: ", box1, "Transformation: ", box2};
                int resp = JOptionPane.showConfirmDialog(null, message, "Parameters of the normalization",
                        JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);

                if (resp == JOptionPane.OK_OPTION) {
                    String method = (String) box1.getSelectedItem();
                    String transform = (String) box2.getSelectedItem();
                    String[] meth = {method};
                    String[] trans= {transform};
                    
                   Normalization norm = new Normalization();
                   norm.setpfad(pfad);
                   norm.setnew(newfile);
                   norm.settrans(trans);
                   norm.setmeth(meth);
                  // norm.start();
                   norm.execute();
                   ....
 }
}
```

Meine Frage lediglich: Muss die Methode doinBackground() immer einen Rückgabetyp haben? Void scheint nicht zu funktionieren.


----------



## Joey85 (18. Jun 2014)

OK hab jetzt den Rückgabetyp auf Void. Jetzt will ich eine ProgressBar erzeugen, die mir den Fortschritt anzeigt.
Initialisiert hab ich sie im GUI-Thread so:

```
double counter = 1.0;
final ProgressMonitor pbar = new ProgressMonitor(monitor, "Normalization...",
"Waiting...", 0, 100);
monitor.setVisible(true);
```
Der Counter wird bei jedem Schleifendurchgang um 1 erhöht und durch die Anzahl der Dateien geteilt, dann der Wert der ProgressBar auf diesen Wert gesetzt.


```
double percent = (counter / (double) file.length) * 100;
                        pbar.setProgress((int) percent);
                        pbar.setNote("Operation is " + (int) percent + "% complete");
                        if (pbar.isCanceled()) {
                            pbar.close();
                            monitor.setVisible(false);
                            return;
                            
                        }
```

Wie kann ich es anstellen, dass die ProgessBar durch den SwingWorker aktualisiert wird, wenn der thread abgearbeitet wurde?


----------



## Joose (18. Jun 2014)

:rtfm:Oracle - SwingWorker hier steht das beschrieben


----------



## Joey85 (18. Jun 2014)

Gut, scheint soweit zu funktionieren.
Jedoch ist mir was aufgefallen:
Ich übergebe dem thread den Counter, um den Progress berechnen zu können. Allerdings ist es irgendwie so, dass der thread nicht in chronologischer Abfolge arbeitet sondern durcheinander. Lasse ich mir den Counter ausgeben sieht das beispielsweise so aus: 1,2,4,5,3,8,6,9,7,10.
Dadurch läuft die ProgressBar natürlich nicht richtig und endet zB bei 85%, wodurch sie sich nicht schliesst am Ende. Wie kann ich also gewährleisten, dass die threads richtig abgearbeitet werden?


----------



## turtle (19. Jun 2014)

Ich hab nicht den ganzen Thread gelesen und gesehen, das jemand den SwingWorker erwähnt hat. 

Dann ist vielleicht mein Blog-Eintrag SwingWorker - Eine Einführung hilfreich?


----------

