1. Liebe Forumsgemeinde,

    aufgrund der Bestimmungen, die sich aus der DSGVO ergeben, müssten umfangreiche Anpassungen am Forum vorgenommen werden, die sich für uns nicht wirtschaftlich abbilden lassen. Daher haben wir uns entschlossen, das Forum in seiner aktuellen Form zu archivieren und online bereit zu stellen, jedoch keine Neuanmeldungen oder neuen Kommentare mehr zuzulassen. So ist sichergestellt, dass das gesammelte Wissen nicht verloren geht, und wir die Seite dennoch DSGVO-konform zur Verfügung stellen können.
    Dies wird in den nächsten Tagen umgesetzt.

    Ich danke allen, die sich in den letzten Jahren für Hilfesuchende und auch für das Forum selbst engagiert haben. Ich bin weiterhin für euch erreichbar unter tti(bei)pcwelt.de.
    Dismiss Notice

Parallele periodische Ausführungen

Discussion in 'Programmieren' started by Miriam1990, Oct 21, 2009.

Thread Status:
Not open for further replies.
  1. Miriam1990

    Miriam1990 Byte

    Code:
    for (int i=0; i<liste.size();i++){	
    
    while (true)
    {
    Thread.sleep(liste[i]*1000);
    //weitere Befehle
    }
    
    }
    
    Hi!
    Hab meinen Code mal in vereinfachter Version dargestellt – is inhaltlich also Quatsch, nur ich denk mal, so isses leichter mein Problem zu verdeutlichen. Ich gehe hier also über eine for-Schleife eine Liste aus int-Elementen durch. Je nachdem, bei welchem Element der Liste der Zähler ist, sollen die Inhalte der while-Schleife in einer unterschiedlichen Periode ausgeführt werden. Leider weiß ich nicht, wie ich das ohne Endlosschleife machen soll – aber eine Endlosschleife ist natürlich absolut ausgeschlossen, weil ich dann nie in mein 2. Element der Liste komme. Ich möchte aber, dass alle Inhalte parallel und jedes in seiner fortlaufenden Periode (also eins eben alle 10 Sekunden, das andere alle 7 Sekunden usw.) ausgeführt wird.

    Hat jemand ne Idee, wie man sowas realisiert? Hab da echt n Brett vorm Kopf x.x

    Miriam
     
  2. kazhar

    kazhar Viertel Gigabyte

    wie w&#228;rs mit timern? jeder eintrag hat seinen eigenen timer und wird - ohne explizites warten - regelm&#228;&#223;ig aufgerufen.

    wenn die liste nicht allzuviele eintr&#228;ge hat k&#246;nntest du auch f&#252;r jeden einen neuen thread aufmachen. und da deine while schleife durchlaufen lassen. (ist aber recht ... unsch&#246;n)
    oder du machts nur eine while schleife, die in der k&#252;rzest m&#246;glichen zeit durchlaufen wird und in der liste nachsieht welches element/welche elemente grade dran ist/sind (eigentlich noch weniger elegant)
     
  3. Miriam1990

    Miriam1990 Byte

    okay.. timer also. empfiehlst du den javax.swing.Timer oder den java.util.Timer?

    also laut "java ist auch eine insel" (http://openbook.galileocomputing.de...16_027.htm#mj02725613e8f7dff2276ff026b0aa3f29) würde das mit javax.swing.Timer ja so aussehen:
    Code:
    javax.swing.Timer t = new javax.swing.Timer( 1000, new ActionListener() { 
      public void actionPerformed( ActionEvent e ) { 
        //blaa
      } 
    }); 
    t.start();  
    
    Da wo ich jetzt blaa hingeschrieben hab, müsste ja dann mein Zeug stehen, was sich immer wiederholen soll, oder? Und anstatt der 1000 würde ich halt meine variablen Zahlen hinschreiben? Stimmt das so vom Prinzip her?

    Das Problem, was bei mir da jetzt auftaucht, is dass das jetzt innerhalb einer for-Schleife steht und er deren int i nicht mag, wenn ich es an der blaa-Stelle verwende, weil es nicht final ist ö.ö ("Cannot refer to a non-final variable i inside an inner class defined in a different method"). Wenn ich dann in der for-Schleife nen final davorschreibe, kommt die Meldung: The final local variable i cannot be assigned. It must be blank and not using a compound assignment.
     
  4. kazhar

    kazhar Viertel Gigabyte

    oh mann, das geschwür java :aua:

    da kannst du den timer mehr oder weniger vergessen, weil du die information, die dein "i" trägt nicht in den action listener hinein kriegst; die variable existiert zur zeit der ausführung nicht mehr und irgendwelche indizes/objekte/.. kannst du dem timer meines wissens nicht übergeben...

    ich würde dann eher auf die variante 3 zurückgreifen. lass jede sekunde eine schleife durchlaufen, die überprüft ob eines der events an der reihe ist.

    dafür müsstest du allerdings deine liste anpassen.
     
  5. Miriam1990

    Miriam1990 Byte

    jahaa, es geht! =))
    musste n bissi rumbasteln, aber jetzt geht's. Vielen Dank! ^^
     
  6. daboom

    daboom Megabyte

    Also ich hätte den java.util.Timer genommen und für jedes i nen TimerTask reingescheduled. In jedem TimerTask wird dann die run() Methode überschrieben und darin halt gemacht, was gemacht werden soll.

    Das Problem mit der final Variablen lässt sich aber einfach lösen, indem vor Instanzierung der anonymen Klasse den gewünschten Wert (also das i) einer final Variablen zuweist. Dann kann man auch inerhalb der anonymen Klasse drauf zugreifen.
     
  7. kazhar

    kazhar Viertel Gigabyte

    war auch meine 1. idee

    problem ist allerdings wenn du nicht weist wieviele eintr&#228;ge in der liste sind und du aber trotzdem f&#252;r jeden eintrag deine eigene run() basteln musst.
    insbesondere dann &#228;rgerlich, wenn die run()'s zwar alle das selbe machen, aber halt z.b. eine variable irgendwo anders auslesen.

    typisch java. kann zwar alles, aber nix vern&#252;nftig ;)
     
  8. daboom

    daboom Megabyte

    Mhh, sehe ich eigentlich kein Problem drin.

    Wenn man eine unbestimmte Anzahl an Tasks (in welcher Form auch immer) starten möchte, können die eigentlich nur alle dasselbe machen. Andernfalls müssten die Aktionen ja bereits durch die Elemente der Liste definiert sein, z.B. durch Runnables.

    Wenn der Task auf irgendeine Variable zugreifen wollen, muss den Tasks halt eine Referenz auf irgend ein Wrapper Objekt mitgegeben werden. Also imo problemfrei möglich.
     
  9. kazhar

    kazhar Viertel Gigabyte

    idee #2...
    dann bist du wieder bei den - im extremfall - zig tausenden threads.
     
  10. daboom

    daboom Megabyte

    Nö, genau einer für den Timer.

    Edit: Also bezogen auf meinen Ansatz... War jetzt nicht mehr so richtig sicher, was Du meintest :grübel:
     
  11. kazhar

    kazhar Viertel Gigabyte

    meine urspr&#252;ngliche idee (die aber mein zugegebenerma&#223;en etwas angestaubtes uni skriptum nicht hergibt) war die java-abwandlung der normalen shell timer.
    also jeder eintrag kriegt einen eigenen timer, die sich aber alle den selben "actionlistener" teilen.
    SetTimer(0, <durchlaufender index=timer_ID>, <zeit zwischen 2 ticks>, TimerCallBack);
    TimerCallBack (=actionlistener) kriegt dann &#252;ber die aufrufparameter die timer_ID und damit den index i mitgeliefert. spielt halt nicht unter java.

    die 2. idee war f&#252;r jeden eintrag in der liste einen thread aufzumachen. der thread kriegt ganz normal beim starten den index mitgeliefert. ob dann dadrin ein timer l&#228;uft oder nicht ist recht egal. nachteil ist die vorher unbekannte anzahl an threads.

    die 3. idee ist die mit der schleife. jede sekunde wird pro eintrag ein zugeh&#246;riger z&#228;hler um 1 erh&#246;ht. wenn der z&#228;hler gleich dem inhalt von liste ist -> z&#228;hler null setzen und tun was getan werden soll.

    im endeffekt muss es aber auch nur funktionieren. gibt sicher noch andere m&#246;glichkeiten, die wahrscheinlich auch eleganter sind.
     
  12. Miriam1990

    Miriam1990 Byte

    hui, da seid ihr ja ziemlich in fachdiskussionen über timer ausgeufert. habs dann nich mehr weiterverfolgt, weil ich erstmal zufrieden war und eh nix verstanden hab...

    jetzt hab ich aber wieder eine sache, wo einer eurer timer vllt ganz angebracht wäre. ich hab ne methode, die auf ne webseite geht und da was überprüft. da es dann passieren kann, dass die Methode keine Rückmeldung bekommt, möchte ich ein timeout einbauen. Ich möchte also selber eine Zeit bestimmen können, nach deren Ablauf die Methode abgebrochen wird und ich dann halt ne dementsprechende Fehlermeldung anhängen kann.

    Wenns einfacher als mit Timer geht, bin ich natürlich auch einverstanden! Ich fänds vor allen dingen ganz gut, wenn ich dafür nicht extra ne neue Klasse oder neue Methoden anlegen müsste (mir is nich ganz klar, ob das nötig ist), weil dann meine struktur wieder unübersichtlicher wird. (Struktur sieht so aus, dass in einer Methode1 die Methode2 aufgerufen wird. Methode2 ist die, die das Timeout braucht und in Methode1 würd ich das dann gerne realisieren..)

    Was ich dazu gefunden hatte, war halt in den javadocs thread.join()
    --> http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.html
    Das hört sich erstmal ganz passend an, aber ich weiß nicht, wie man das dann aufbaut - bin noch bisschen schlecht darin, diese docu richtig lesen zu können..
     
  13. daboom

    daboom Megabyte

    Nä, join() ist hier verkehrt, da dort ja keine zwei Threads laufen, so wie ich Dich verstanden habe.

    es sei denn Du machst es in etwa folgendermaßen:

    PHP:
    public void Methode1() {
      final 
    Thread t = new Thread() {
        public 
    void run() {
          
    Methode2();
        }
      };

      
    t.start();
      
    t.join();
    }
    Dann würdest Du Methode2 in einem extra Thread aufrufen. Das join() setzt aber voraus, dass der Aufruf von Methode2() auch irgendwann fertig wird. Womit das Starten in einem extra Thread hier sinnfrei ist, da der aktuelle Thread ohnehin auf den anderen wartet, könnte er Methode2() auch gleich selbst aufrufen. (Ich hoffe, Du verstehst, was ich meine)

    Im einfachsten Fall könnte man das von oben etwas modifizieren:

    PHP:
    public void Methode1() {
      final 
    AtomicBoolean success = new AtomicBoolean(false);

      final 
    Thread t = new Thread() {
        public 
    void run() {
          
    Methode2();

          
    success.set(true);
        }
      };

      
    t.start();
      
      try {
        
    Thread.sleep(timeout);
      } catch (final 
    InterruptedException e) {
        
    // Ignorieren, eigentlich nicht so schön, da der Timeout jetzt nich
        //  hinhaut, aber erstmal egal ;)
      
    }

      if (
    success.get()) {
        
    // Methode2() wurde rechtezeitig beendet
      
    } else {
        
    // Methode2() ist immer noch am Machen
      
    }
    }
    Damit würdest Du allerdings die Ausführung des zweiten Threads noch nicht abbrechen. Das ist aber ohnehin nicht ohne weiteres möglich.
    Du könntest prinzipiell Thread.interrupt() auf dem gestarteten Thread aufrufen, das heißt aber nicht unbedingt, dass das interrupt nicht irgendwo in den Tiefen von Methode2() abgefangen wird.

    Was macht denn Methode2() genau?
     
  14. Miriam1990

    Miriam1990 Byte

    hmm schade, so ungefähr, wie es in deinem ersten codefragment ist, hatte ich mir das vorgestellt. Allerdings mit der Variante des joins, wo man in der Klammer noch ne Millisekundenzahl angibt, aber das bringt dann wohl genausowenig, weil der also einfach nur wartet, bis die Methode andere fertig is..

    also hier kommt jetzt so ziemlich alles zusammen, wobei du mir schonmal geholfen hast..
    wir hatten doch mal die sache mit der ArrayList aus Objekten der Klasse Target. In Target gibt es u.a. die Attribute url, periode und timeout.
    In der Methode2 -eigentlich "prüfungDurchführen" - werden dann überprüfungen (mit jwebunit) der angegebenen url durchgeführt.
    Und Methode1 - bei mir "periodischAufrufen()" - soll nun realisieren, dass jedes einzelne Target in dem angegebenen Abständen aufgerufen wird (wenn periode=10, dann alle 10sec) und dass eben das timeout realisiert wird.
    das mit der periode hatte ich ja dann so gemacht, dass halt die sekunden immer runtergezählt werden - is halt ziemlich unelegant, weil damit die zeit, die die methode zum ausführen braucht, nich mitgezählt wird..

    ich wäre jetzt auch nicht abgeneigt davon, die sache mit der periode jetzt doch nochmal umzuändern, wenn ich jetzt eh versuche mich in threads oder timer (was man halt braucht..) einzuarbeiten.

    dein codefragment ist ja schon ganz cool, also es läuft schonmal und er erkennt, wenn die zeit überschritten wird.
    naja und das abrechen ist aber dann schon wichtig, oder? weil sonst ist der ja irgendwann am gleichen target mit mehreren prozessen beschäftigt und kommt nich zu nem ergebnis. oder kann es sein, dass der sich dann von selbst einfach irgendwann aufhängt und nen fehler ausgibt? dann wärs ja eigentlich schön, dann muss ich nur die exception auffangen und er bricht sozusagen von selber ab.

    ich häng dir mal meinen code an, dann kannst dus bestimmt besser nachvollziehen:
    Code:
    public static void periodischAufrufen (){
    		
    		ArrayList <Integer> perioden = new ArrayList <Integer>();
    		
    		for (int i=0; i<targetliste.size();i++){			//vorher alle Perioden merken			
    			Target aktuellesTarget = (Target) targetliste.get(i);
    			//if (String.valueOf(aktuellesTarget.periode)!="")
    			if (aktuellesTarget.periode!=0)
    			perioden.add(aktuellesTarget.periode);
    			else{									//wenn keine periode angegeben
    			aktuellesTarget.periode=3;	 			//default Wert von 3 Sek.
    			perioden.add(aktuellesTarget.periode);
    			}
    		}
    		
    		int sekunde=1;//nur für die Prüfausgabe
    		
    		while (true){				
    			
    			for (int i=0; i<targetliste.size();i++){		//Targets durchgehen	
    				final Target aktuellesTarget = (Target) targetliste.get(i);
    				aktuellesTarget.periode--;						
    				
    				if (aktuellesTarget.periode==0&&aktuellesTarget.url!=""){
    					System.out.println ("Target "+i );
    					
    			//--------------hier beginnt deine Idee--------------------
    					  final AtomicBoolean success = new AtomicBoolean(false);
    
    					  final Thread t = new Thread() {
    					    public void run() {
    					    	try {
    					    		prüfungDurchführen (aktuellesTarget);
    							}catch (Throwable p){System.out.println ("Im PrüfungDurchführenCatch");}
    
    					      success.set(true);
    					    }
    					  };
    
    					  t.start();
    					  
    					  try {
    					    Thread.sleep(5000);//meine timeout angabe
    					  } catch (final InterruptedException e) {
    					    // Ignorieren, eigentlich nicht so schön, da der Timeout jetzt nich
    					    //  hinhaut, aber erstmal egal ;)
    					  }
    
    					  if (success.get()) {
    					    // Methode2() wurde rechtezeitig beendet
    						  System.out.println ("Rechtzeitig fertig");
    					  } else {
    					    // Methode2() ist immer noch am Machen
    						  t.interrupt();
    						  System.out.println ("Zu langsam");
    					  }//--------------Ende deine Idee--------------------
    		
    				aktuellesTarget.periode=perioden.get(i);				
    				}			
    			}//Ende eines Targets	
    			
    			try{
    			Thread.sleep(1000);}//jede Sekunde schauen
    			catch (Exception e){}
    			
    			sekunde++;
    			System.out.println ("Start von Sekunde "+sekunde);
    		}//Ende while 		
    	}
     
  15. daboom

    daboom Megabyte

    Gut okay, jetzt wei&#223; ich aber immer noch nicht, was Methode2 (in Deinem Fall jetzt "pr&#252;fungDurchf&#252;hren()") macht...

    Wie gesagt, man kann prinzipiell interrupt() benutzen, um den jeweiligen Thread anzuhalten (interrupt() allein h&#228;lt ihn nicht an, unterbricht ihn aber in seiner momentanen bzw. n&#228;chsten blockierenden Operation, danach muss man dann halt daf&#252;r sorgen, dass er seine run() Methode verl&#228;sst).

    Das Problem ist halt nur, dass man daf&#252;r wissen m&#252;sste, was dort so alles an blockierenden Aktionen kommt. Allein schon wenn einfach zwei hintereinander kommen und Du rei&#223;t den Thread aus der ersten mit interrupt() raus, geht danach gleich in die zweite und blockiert weiter. Mal so als Beispiel ;)

    Also beschreibe bitte noch die pr&#252;fungDurchf&#252;hren() Methode.

    Edit: Deine "targetList" ist ja immer noch Raw und nicht mit "Target" generifiziert... :D

    Edit2: Die "periodischAufrufen()" Methode kommt doch nie zum Ende, so wie ich das sehe, oder? Au&#223;er es wird irgendwo ne RuntimeException geworfen. Ist die so gedacht? Ich denke, ich h&#228;tte es anders verstanden, also, dass die wirklich periodisch aufgerufen werden soll...
     
    Last edited: Dec 17, 2009
  16. Miriam1990

    Miriam1990 Byte

    okay. also in der methode prüfungDurchführen() werden einmal über Log4j einige Emails versendet und Logfiles erstellt. Da sollte es noch kein Problem geben - weil das einzige, was da nich funzen könnte, is wenn es die email-adresse nicht gibt und dann gibts ja direkt nen fehler, den ich auffangen kann (sprich hierfür braucht man das timeout nich, weil er nicht hängenbleiben dürfte)

    und dann werden noch 3 Methoden ausgeführt und deren Rückgabewerte verarbeitet. und um die 3 Merthoden gehts eigentlich. Das sind halt 3 Testfälle, die ich mit dem Framework JWebUnit realisiert habe, weiß nich ob du das kennst.. Naja die erste Methode überprüft den Statuscode der url. Die zweite Methode schaut, ob auf der Seite ein bestimmtes Suchwort vorhanden ist und die dritte Methode gibt einfach die komplette Seite zurück.

    joa, das is ne endlos-schleife in der periodischAufrufen() Methode. Ist auch schon so gedacht, das soll halt endlos lang bestimmte webseiten überprüfen (in den abständen, wie sie halt in 'periode' angegeben sind)
     
  17. daboom

    daboom Megabyte

    Dann bleibt die Frage, welche der 3 Aufrufe dort ewig bzw. zu lange blockieren kann?

    Wenn das auf jede zutrifft, brauchst Du prinzipiell ein boolean Flag, welches dazu gebraucht wird, abzupr&#252;fen, ob die weiteren beiden Methoden &#252;berhaupt noch aufgerufen werden sollen, also ob der Thread, der die Methoden aufruft, bereits beendet werden sollte.

    Wenn das ganze auf Methodenebene weiter gemacht werden soll (also nicht extra ein Objekt f&#252;r jeden Aufruf von pr&#252;fungDurchf&#252;hren() instanizert werden soll), s&#228;he das in etwa so aus:

    In deiem JWebUnit Code:

    PHP:
    public void pruefungDurchfuehren(final Target aktuellesTarget, final AtomicBoolean shouldStop) {
      
    // Dein anderer JWebUnit Krams

      
    ersteMethode();

      if (!
    shouldStop.get()) {
        
    zweiteMethode();
      }

      if (!
    shouldStop.get()) {
        
    dritteMethode();
      }
    }
    In der periodischAufrufen():

    PHP:
    final AtomicBoolean success = new AtomicBoolean(false);
    final 
    AtomicBoolean shouldStop = new AtomicBoolean(false);

    final 
    Thread t = new Thread() {
      public 
    void run() {
        try {
          
    pruefungDurchfuehren (aktuellesTargetshouldStop);
        } catch (
    Throwable p) {
          
    System.out.println ("Im Pr&#252;fungDurchf&#252;hrenCatch");
        }

        
    success.set(true);
      }
    };

    t.start();

    try {
      
    Thread.sleep(5000);
    } catch (final 
    InterruptedException e) {
      
    // Ignorieren, eigentlich nicht so sch&#246;n, da der Timeout jetzt nich
      //  hinhaut, aber erstmal egal ;)
    }

    if (
    success.get()) {
      
    // Methode2() wurde rechtezeitig beendet
      
    System.out.println ("Rechtzeitig fertig");
    } else {
      
    // Methode2() ist immer noch am Machen
      
    shouldStop.set(true);
      
    t.interrupt();
      
    System.out.println ("Zu langsam");
    }
    Hier wird jetzt (relativ umst&#228;ndlich) &#252;ber die shouldStop Variable der jWebUnit Methode mitgeteilt, ob sie abbrechen soll (also die weiteren Methoden &#252;berhaupt noch aufrufen soll) wenn der Thread unterbrochen wird.

    Gesetzt den Fall, dass innerhalb der drei Methoden im jWebUnit Teil InterruptedExceptions nicht derart abgefangen werden, dass trotzdem einfach weitergemacht wird (z.B. durch ignorieren und eine Endlosschleife fortsetzen), sollte der Thread so immer abbrechen, wenn der Timeout abgelaufen ist.
     
  18. Miriam1990

    Miriam1990 Byte

    das scheint zu funtktionieren^^
    viiiielen dank! :bussi:
     
  19. Miriam1990

    Miriam1990 Byte

    mhh jetzt is mir da was aufgefallen. das is ja doch nich ganz optimal.. weil da wird ja dann IMMER solange gewartet, wie halt das timeout is. sprich, egal wie lange die abarbeitung des codes dauert, es wird immer so lange gewartet um zu schauen ob er fertig is -auch wenn alles total schnell und ohne probs funktioniert hat.
    ich hab halt überlegt, ob man da jetzt so ne etwas kürzere standardzeit reinsetzt und wenn er dann fertig is, dass es halt dann weiter geht und nur, wenn in der kürzeren zeitspanne nicht fertig geworden ist, dass dann die timeout-zeitvorgabe abgewartet wird. aber wirklich elegant ist das ja auch nicht..
    gibt es dafür nicht irgendwie einen besseren weg? das problem dürften doch schon andere menschen vor mir gehabt haben.. ö.ö
     
  20. Miriam1990

    Miriam1990 Byte

    mh ok hat sich erledigt. habs hinbekommen =)
     
Thread Status:
Not open for further replies.

Share This Page