Thread pausieren lassen (wait()?)



  • Hi,

    wie kann ich einen Thread pausieren lassen, bis ein bestimmtes Ereignis eintritt?

    Ich erstelle in meinem Hauptthread einen neuen Thread, der eine lange dauernde Arbeit ausführen soll und starte ihn:

    // in WNTest.main(String[]):
    WNTest test1 = new WNTest();
    Thread thread1 = new Thread(test1);
    thread1.start();
    
    // ==============================================
    
    // in WNTest.run():
    public void run() {
    	for (int i = 1; i <= 500; ++i) {
    		System.out.println(compute(i));
    	}
    }
    

    Wie kann ich die Ausführung von run() nun pausieren lassen? D.h. der Thread, der run() ausführt soll nicht weitermachen und die Rechenzeit den anderen Threads überlassen. Ich hätte gerne Methoden wie pause() und unpause(), schaffe es aber nicht, diese zu schreiben. Ich habe mit wait() herumexperimentiert, aber habe immer nur IllegalMonitorStateExceptions bekommen, ich nehme an ich habe irgendwo noch einen Denkfehler...

    Danke schonmal! 🙄



  • Thread.sleep(666);



  • wait() notify() synchronized(monitor)



  • Also sleep kommt nicht in Frage da es erstens ja "aktives Warten" ist, also CPU Zeit kostet, und zweitens ja nicht auf unbestimmte Zeit funktioniert.
    wait(), notify() und synchronized(monitor) scheint mir richtig zu sein, nur bekomme ich's halt nicht hin:

    public class WNTest implements Runnable {
    	Object monitor = new Object();
    	public int compute(int n) {
    		return (n < 2) ? 1 : compute(n-1) + compute(n-2);
    	}
    
    	public void pause() throws Exception {
    		synchronized (monitor) {
    			wait();
    		}
    	}
    
    	public void run() {
    		for (int i = 1; i <= 5; ++i) {
    			System.out.println(compute(30+i));
    		}
    	}
    	public static void main(String[] args) {
    		try {
    			WNTest test = new WNTest();
    			Thread thread = new Thread(test);
    			thread.start();
    			test.pause();
    		} catch (Exception ex) {
    			ex.printStackTrace();
    		}
    	}
    }
    

    Wenn ich das laufen lasse, bekomm ich eine IllegalMonitorStateException:

    java.lang.IllegalMonitorStateException
    	at java.lang.Object.wait(Native Method)
    	at java.lang.Object.wait(Object.java:474)
    	at WNTest.pause(WNTest.java:9)
    	at WNTest.main(WNTest.java:23)
    

    Habt ihr ne Idee?

    Danke!!



  • Also sleep kommt nicht in Frage da es erstens ja "aktives Warten" ist, also CPU Zeit kostet

    Nee sleep legt den Thread schlafen. Eine Endlosschleife währe ein aktives Warten.
    Man könnte natürlich den Thread eine bestimmte Zeit schlafen legen (100 ms oder so) und prüfen ob ne Variable gesetzt ist zum weiterlaufen... Also nicht nur ne Endlosschleife sondern eine die sich ein bischen schlafen legt... usw.

    Man könnte das auch so machen, mit nem Monitor oder mit der Semaphore Klasse von Java.

    public class Test2 {
    
    	public static void main(String[] args) {
    		new Test2();
    	}
    
    	Test2() {
    		MyThread myThread = new MyThread();
    		myThread.start();
    
    		try {
    			Thread.sleep(4015);
    
    			System.out.println("Mache Pause");
    			myThread.pause();
    
    			Thread.sleep(4000);
    
    			System.out.println("Keine Pause mehr");
    			myThread.unpause();
    
    			Thread.sleep(4000);
    
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    
    	}
    
    	class MyThread extends Thread {
    		MyThread() {
    			ob = new Object();
    		}
    
    		private int counter = 0;
    
    		private final Object ob;
    
    		private boolean makeABreak = false;
    
    		public void run() {
    
    			while (true) {
    				Object o = this.ob;
    				synchronized (o) {
    
    					if (makeABreak) {
    						try {
    
    							o.wait();
    						} catch (InterruptedException e) {
    							// TODO Auto-generated catch block
    							e.printStackTrace();
    						}
    					}
    					++counter;
    					System.out.println("Hallo Zeile Nr.:\t" + counter);
    
    					try {
    						this.sleep(500);
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    				}
    			}
    		}
    
    		public void pause() {
    			makeABreak = true;
    		}
    
    		public void unpause() {
    			makeABreak = false;
    			Object o = this.ob;
    			synchronized (o) {
    				o.notifyAll();
    			}
    		}
    	}
    
    }
    


  • Danke für deinen Post!

    Ich glaube folgendes Problem entdeckt zu haben:
    In Zeile 51 wird (in einem synchronized(o) Block!) o.wait(); ausgeführt.
    Angenommen mein Arbeiterthread ist in diesem wait und ich rufe von einem anderen Thread aus unpause() auf, dann wird dieser Aufruf doch bei Zeile 77 blockieren, da ja der Arbeiterthread das Lock auf o hat, oder?

    Frohe Ostern,
    Waiter



  • Das ist ne gute Frage.
    Also funktionieren tut der Code.

    Eigentlich können mehrere Threads auf das Objekt o zugreifen nur das synchronized schützt es exklusiv. Man muss bei dem synchronized auch das gleiche Objekt benutzen.

    Also um auf deine Frage zurückzukommen würde ich sagen das wenn ein Thread o.wait aufruft es sich nicht mehr im Kritischen Abschnitt befindet. Der Thread hängt in der Warteschlange des Objekt o und somit kann ein anderer Thread in den Kritischen Abschnitt und o.nitifyAll() aufrufen.


Anmelden zum Antworten