# thread anhalten und wieder starten



## danielm (21. März 2005)

hey,
also ich hab folgendes problem, ich möchte einen thread kurz anhalten, etwas anderes machen lassen und danach den thread wieder weiter laufen lassen


```
jmonc.Main.Status.suspend();
        socket.SendMsg(dialmode);
        jmonc.Main.Status.resume();
```

so hab ich mir das gedacht, der thread stoppt zwar, aber er läuft nicht wieder an... was mache ich da falsch?!   

mfg daniel


----------



## Snape (21. März 2005)

danielm hat gesagt.:
			
		

> ```
> jmonc.Main.Status.suspend();
> ```



Aua. So ein Code tut in der Seele weh. Schon mal was von OO, Kapselung und getter-setter gehört?



> so hab ich mir das gedacht, der thread stoppt zwar, aber er läuft nicht wieder an... was mache ich da falsch?!
> 
> mfg daniel



Üblicherweise gibt es für Threads die Methoden start(), interrupt(), sleep() usw., steht alles in der API. Doort steht übrigens auch:

void resume()
*Deprecated*. This method exists solely for use with suspend(), which has been deprecated because it is deadlock-prone. For more information, see Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?.


----------



## danielm (21. März 2005)

naja, ich denke jmonc.Main.Status.suspend() hat schon was mit OO zutun...

aber wir bekomme ich dann den thread zum stoppen?!


----------



## Thomas Darimont (21. März 2005)

Hallo!

Schau doch mal hier:

```
/**
 * 
 */
package de.tutorials;

import java.util.Timer;
import java.util.TimerTask;

/**
 * @author Administrator
 * 
 */
public class ThreadExample {

	private boolean pause;

	private Object lock = new Object();

	private Thread runner = new Thread() {
		public void run() {
			int i = 0;
			while (true) {
				if (pause) {
					synchronized (lock) {
						try {
							lock.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
				System.out.println(i++);

				try {
					sleep(500L);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	};

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		new ThreadExample().doIt();
	}

	private void doIt() {
		runner.start();
		Timer timer = new Timer();
		TimerTask task = new TimerTask() {
			public void run() {
				pause = true;

				for (int i = 0; i < 10; i++) {
					System.out.print("bla: ");
					System.out.println(i);
					try {
						Thread.sleep(100L);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				synchronized (lock) {
					lock.notify();
				}

				pause = false;
			}
		};
		timer.schedule(task, 5000L); // In 5 Sekunden starten...

	}

}
```

Gruß Tom


----------



## Thomas Darimont (21. März 2005)

...oder mit Java 5 Mitteln:

```
/**
 * 
 */
package de.tutorials;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Administrator
 * 
 */
public class ThreadExample {

	private Lock lock = new ReentrantLock();

	private Thread runner = new Thread() {
		public void run() {
			int i = 0;
			while (true) {
				try {
					lock.lock();

					System.out.println(i++);

					try {
						sleep(500L);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				} finally {
					lock.unlock();
				}

			}
		}
	};

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		new ThreadExample().doIt();
	}

	private void doIt() {
		runner.start();
		Timer timer = new Timer();
		TimerTask task = new TimerTask() {
			public void run() {
			   try {
				lock.lock();
				for (int i = 0; i < 10; i++) {
					System.out.print("bla: ");
					System.out.println(i);
					try {
						Thread.sleep(100L);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
   			   }finally{
				lock.unlock();
   			   }
			}
		};
		timer.schedule(task, 5000L); // In 5 Sekunden starten...

	}

}
```

Gruß Tom


----------



## Snape (21. März 2005)

danielm hat gesagt.:
			
		

> naja, ich denke jmonc.Main.Status.suspend() hat schon was mit OO zutun...



Ehrlich gesagt nicht viel. Das sieht nach schlechtem C++ Ursprung aus, wie er leider immer wieder üblich ist und praktiziert wird.


----------



## danielm (21. März 2005)

Snape hat gesagt.:
			
		

> Ehrlich gesagt nicht viel. Das sieht nach schlechtem C++ Ursprung aus, wie er leider immer wieder üblich ist und praktiziert wird.



naja, wie macht man es denn richtig? wir haben das so an der uni gelernt...


----------



## Snape (21. März 2005)

*Seufz* Ich weiß, dass an den Hochschulen sowas gelehrt wird. Du bist nicht der erste, nicht der einzige und sicher nicht der letzte, der nicht vernünftig OOP gelehrt bekommt.
Richtig wäre es, nicht auf die Objekte direkt zuzugreifen, sondern per get...() und ggf in Zwischenvariablen halten. Man mag durchaus anderer Auffassung sein und getter und setter nicht für notwendig erachten, wenn sie nur ein return meineVariable enthalten, aber es wäre sauber und konsequent OO.
Also besser - wenn auch noch fehlerträchtig, wenn die get-Methoden nicht sauber implementiert sind  - wäre:

jmonc.getMain().getStatus().resume();

und die Steigerung
Main myMain = jmonc.getMain();
if (myMain != null)
  Status myStatus = myMain.getStatus();
  if ( myStatus != null )
    myStatus.resume();

Außerdem gibt es noch die ganz saubere Möglichkeit:
Startklasse:
jmonc.resumeThread();

dessen Implementierung:

public void resumeThread()
{ getMain().resumeStatusThread() }

in Main:
public void resumeStatusThread()
{ getStatus().resumeYourThread() }

Und in Status:
public void resumeYourThread()
{ resume() }

Im OO-Sinne ist das letzte Beispiel sauber gekapselt und vorbildlich.


----------



## Thomas Darimont (21. März 2005)

Hallo!



> Im OO-Sinne ist das letzte Beispiel sauber gekapselt und vorbildlich.


In "deinem" OO-Sinne... man kanns auch übertreiben...

Wenn man sich im Sichtbarkeitsbereich von Membervariablen befindet braucht man IMHO keine getter zu bemühen. Das Geheimnisprinzip das dem Zugriff über getter und setter zugrunde liegt zählt meines erachtens nur für Fremde Objekte. Ein Argument für den Zugriff über setter oder getter auf Membervariablen der gleichen Instanz wäre etwa wenn dort noch weitere Logik getriggert werden würde (z.Bsp. wenn das Datum des letzten Zugriffs zwischengespeichert werden würde etc.)

Gruß Tom


----------



## chell (21. März 2005)

Thomas Darimont hat gesagt.:
			
		

> Hallo!
> 
> 
> In "deinem" OO-Sinne... man kanns auch übertreiben...
> ...


 

 Hallo,

 ich habe das ganze so gelernt: 
 Man soll nie auf die Eigenschaften einer Klasse (bzw. Objektes) direkt zugreifen. Es sollten immmer Methoden definiert werden, die das machen.

 Wie weit er OOP umsetzt, ist aber meiner Meinung nach jedem selbst überlassen.


----------



## Thomas Darimont (21. März 2005)

Hallo!

So so, also wäre die Methode inc2 besser als die Methode inc ? Das denke ich nicht...
Wie gesagt wenn die Attribute eines Objektes innerhalb des Objektes verwendet werden reicht IMHO ein einfacher Verweis mit this... solange keine Zusatzlogik in die get/set Methoden gesteckt worden ist. Soll von "außen" von einem Fremden Objekt auf ein Attribut eines anderen Objektes zugegriffen werden, so sollte der Zugriff natürlich über getter/setter erfolgen.

```
/**
 * 
 */
package de.tutorials;

/**
 * @author Administrator
 * 
 */
public class Foo {

	private int value;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println(new Foo().inc());
		System.out.println(new Foo().inc2());
	}

	private int inc() {
		return ++this.value;
	}

	private int inc2() {
		setValue(getValue() + 1);
		return getValue();
	}

	private int getValue() {
		return value;
	}

	private void setValue(int value) {
		this.value = value;
	}
}
```

Gruß Tom


----------



## Snape (21. März 2005)

Thomas Darimont hat gesagt.:
			
		

> Hallo!
> 
> So so, also wäre die Methode inc2 besser als die Methode inc ? Das denke ich nicht...
> Wie gesagt wenn die Attribute eines Objektes innerhalb des Objektes verwendet werden reicht IMHO ein einfacher Verweis mit this... solange keine Zusatzlogik in die get/set Methoden gesteckt worden ist. Soll von "außen" von einem Fremden Objekt auf ein Attribut eines anderen Objektes zugegriffen werden, so sollte der Zugriff natürlich über getter/setter erfolgen.
> Gruß Tom



Einverstanden. Schließlich sollte ein Objekt die eigenen  Variablen kennen und damit auch ansprechen dürfen.


----------



## Thomas Darimont (21. März 2005)

Hallo!

Das sagte ich doch 

Gruß Tom


----------



## torsch2711 (23. März 2005)

Hehehe,

 was für eine Diskussion 

 Natürlich sollte man den Code sauber halten und sich an gewisse OO-Praktiken halten, im Endeffekt ist es aber jedem sein eigener Stil und man sollte es so lassen, wenn sich derjenige damit wohlfühlt (lesbarkeit ist wieder ein anderes Thema). Hab in meinem bisherigen leben soviel "Code-Müll" vom stil her gesehen, das ich denke schlimmer gehts immer....

 Muss zugeben, das ich bis vor 2 Jahren auch kein sauberer Programmierer war, habe allerdings eingesehen, dass einige Konzepte und Stile einzuhalten sind, damit man später selbst noch durchsteigt 

 Gruss
 Torsten


----------



## Snape (23. März 2005)

Wartbarkeit und Fehleranfälligkeit sind ausreichende Gründe. Mir ist allerdings schon klar, dass man niemanden dazu zwingen kann, sauber OO zu programmieren.


----------



## slang (6. April 2006)

Hi,

ich habe ein ähnliches Problem, aber erst mal mein Code.


```
/**
	 * 
	*/
	public void mousePressed(MouseEvent arg0) {
			
		System.out.println("Wie oft wirst du eigentlich....");
		
		timer = new Thread() {					
			public void run() {
			        while(true) {

                                        if(isInterrupted())
					         break;
					try {
						sleep(1000L);
						showNext();	
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}													
				}						
			}					
		};
		timer.start();								
	}
			
	/**
	 * 
	 */
	public void mouseReleased(MouseEvent arg0) {
		System.out.println("Timer gestoppt");
		timer.interrupt();				
	}
```

Ziel: 
Wenn die Maustaste gedrückt und gehalten wird, soll er alle 1000 Millisekunden (?) die Funktion showNext() aufrufen. Sobald die Maustaste losgelassen wird, soll er damit aufhören. 

Problem:
Obwohl die Ausgabe "Timer gestoppt" auf die Konsole kommt, läuft der Thread immer weiter, wenn die Maustaste losgelassen wird. Wieso?


----------



## Thomas Darimont (6. April 2006)

Hallo!

Also ich würde da soch machen:

```
/**
 * 
 */
package de.tutorials;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.Timer;

/**
 * @author Tom
 *
 */
public class RestartableTimerExample extends JFrame{

    Timer timer;
    JButton btnTimerControl;
    JTextField txtTime;
    
    public RestartableTimerExample(){
        super("RestartableTimerExample");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        
        timer = new Timer(250,new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                txtTime.setText("" + System.currentTimeMillis());
            }
        });
        
        btnTimerControl = new JButton("Start");
        btnTimerControl.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                if(timer.isRunning()){
                    timer.stop();
                    btnTimerControl.setText("Start");
                }else{
                    timer.start();
                    btnTimerControl.setText("Stop");
                }
            }
        });
        
        txtTime = new JTextField(20);
        add(txtTime,BorderLayout.NORTH);
        add(btnTimerControl,BorderLayout.SOUTH);
        
        pack();
        setVisible(true);
    }
    
    /**
     * @param args
     */
    public static void main(String[] args) {
        new RestartableTimerExample();
    }

}
```

Gruß Tom


----------



## slang (7. April 2006)

Wunderbar, das funktioniert, vielen Dank


----------



## PositivDenker (3. Februar 2009)

Hallo Thomas!
Warum macht Ihr Code nicht gleiche Ergebnisse?
Manchmal erwacht es mit "Bla:" , aber meistens schläft Bla-Thread weiter...
Ist es wahrscheinlich SUN dafür verantwortlich ?


Link hier: http://www.tutorials.de/tutorials197327.html&highlight=Thread+starten+stoppen


----------



## fjfvo (5. Februar 2009)

Hallo zusammen,

diesen Code führt zu dem gleichen Ergebnis:
man sollte das Lock so kurz wie möglich halten,
und im finally Block wieder freigeben..


```
package de.tutorials;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Thomas Darimont
 * 
 */
public class ThreadExample {

    private Lock lock = new ReentrantLock();

    private Thread runner = new Thread() {
        public void run() {
            int i = 0;
            while (true) {
                try {
                    lock.lock();
                    System.out.println(i++);
                } finally {
                    lock.unlock();
                }
                try {
                    sleep(500L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };

    /**
     * @param args
     */
    public static void main(String[] args) {
        new ThreadExample().doIt();
    }

    private void doIt() {
        runner.start();
        Timer timer = new Timer();
        TimerTask task = new TimerTask() {
            public void run() {
                try {
                    lock.lock();
                    for (int i = 0; i < 10; i++) {
                        System.out.print("bla: ");
                        System.out.println(i);
                        try {
                            Thread.sleep(100L);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                } catch (RuntimeException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };
        timer.schedule(task, 5000L); // In 5 Sekunden starten...
    }
}
```


----------

