# mehrere Threads verwalten?



## Gast (17. Mrz 2008)

Hallo,
ich habe eine relativ komplexe Anwendung welche die Abarbeitung von mehreren Datein vornimmt.
Es werden z.B. 100 files geladen und irgendwas damit gemacht und wieder gespeichert.

Zur zeit ist es so das ein file nach dem anderen abgearbeitete wird.

Ich wollte jetzt die Abarbeitung gleichzeitig mit Thread laufen lassen.

Ist natürlich nicht so gut z.B. 100 Threads aufzumachen oder auch mehr.
Da gibts ja immer ne OutOfMemoryException.

Weis jemand wie ich das am geschicktesten Regeln kann?

Dachte mir z.B. immer 5 Threads laufen zu lassen, oder gibts vielleicht ne 
Möglichkeit das automatisiert laufen zu lassen.

Also so viele Threads wie mögliche ohne das es eine Exception gibt?



Danke schonmal für euere Antworten.


----------



## Niki (17. Mrz 2008)

Du brauchst einen ThreadPool der Threads startet. Diese Threads warten bis etwas in eine Queue gelegt wird und holen das automatisch ab. Müsste so aussehen:

WorkerThread:


```
import java.util.NoSuchElementException;

public class WorkerThread implements Runnable {
	
	private ThreadPool pool = null;
	
	public WorkerThread(ThreadPool pool){
		this.pool = pool;
	}

	public void run() {
		while(true){
			try{
				Runnable r = pool.getNextRunnable();
				r.run();
			}catch(NoSuchElementException ex){
				synchronized(pool){
					try {
						pool.wait();
					} catch (InterruptedException e) {						
					}
				}
			}
		}
	}

}
```

ThreadPool:

```
import java.util.LinkedList;
import java.util.NoSuchElementException;

public class ThreadPool {

	private LinkedList<Runnable> runnables = null;

	public ThreadPool(int count) {
		runnables = new LinkedList<Runnable>();
		for (int i = 0; i < count; i++) {
			new Thread(new WorkerThread(this)).start();
		}
	}

	public synchronized Runnable getNextRunnable()
			throws NoSuchElementException {
		return runnables.removeFirst();
	}

	public synchronized void addRunnable(Runnable r) {		
		runnables.add(r);
		notifyAll();
	}
}
```

TestKlasse:

```
public class StartThreadPool {
	public static void main(String[] args) {
		ThreadPool pool = new ThreadPool(10);
		for(int i = 0; i < 100; i++){
			final int num = i;
			pool.addRunnable(new Runnable(){
				public void run() {
					System.out.println(num + " working");
					try {
						Thread.sleep(5000);
					} catch (InterruptedException e) {
						
					}
					System.out.println(num + " finished");
				}
			});
		}
		System.out.println("100 Jobs added");
	}
}
```


----------



## tfa (17. Mrz 2008)

Ab Java 5 gibt es das Concurrency-Framework. Das ist alles drin, was man braucht (bevor du anfängst, selbst was zusammen zu frickeln).


----------



## quippy (17. Mrz 2008)

Mmmh, mit ist da was aufgefallen, was zu einem Problem werden könnte:

Wenn man in einer Runnable::run()-Methode eine (Endlos-)schleife baut und dort viel unternimmt, ohne mal einen Thread.sleep(..) einzubauen, wird keine Zeit an die anderen Threads mehr abgegeben (kooperatives Multitasking in Java?)

Daher könnte deine ThreadPool-Worker-Methode die gesamte VM etwas lahmlegen. Eine Alternative hätte ich für die spezielle Methode allerdings auch nicht so direkt parat, da Du ja an die Worker-Methode des eigentlichen Threads weiterleitest - man müßte dort also aufpassen.


----------



## Niki (17. Mrz 2008)

Richtig, der *eigentliche* Worker muss dafür sorgen, dass er nicht die gesamte CPU frisst.


----------



## Guest (17. Mrz 2008)

Danke erstemal für die detailierte Antwort.

Habe das jetzt so implementiert wie du beschreiben hattest.
Bekomme aber jetzt folgende Exception:

```
Exception in thread "Thread-9" java.lang.OutOfMemoryError: Java heap space
```

??


----------



## Gast (17. Mrz 2008)

sorry jetzt erst dioe letzten Posts gesehen probiere das mal mit nen paar Sleeps.


----------



## tfa (17. Mrz 2008)

quippy hat gesagt.:
			
		

> Wenn man in einer Runnable::run()-Methode eine (Endlos-)schleife baut und dort viel unternimmt, ohne mal einen Thread.sleep(..) einzubauen, wird keine Zeit an die anderen Threads mehr abgegeben (kooperatives Multitasking in Java?)



Wie meinst du das? Die anderen Threads werden _gar nicht_ mehr ausgeführt? Das stimmt so nicht ganz. Normalerweise werden unter Java normale (betriebssystem-seitige) Threads (d.h. präemtives Multitasking) benutzt. In der Frühzeit von Java (und unter bestimmten Plattformen sicherlich auch noch heute), verwendete man Green Threads, die nur kooperativ funktionieren. Heute sollte das kein Problem mehr sein.


----------



## Guest (17. Mrz 2008)

Habs jetzt so wie hier beschrieben implementiert und auch ein paar Sleeps eingebaut.

Bekomme aber immer noch folgende Exception:

```
Exception in thread "Thread-9" java.lang.OutOfMemoryError: Java heap space
```

 :?:


----------



## quippy (17. Mrz 2008)

tfa hat gesagt.:
			
		

> quippy hat gesagt.:
> 
> 
> 
> ...



Meine Erfahrung (und es mag sein, daß ich da was falsch implementiert habe!) hat gezeigt, daß die VM sehr langsam reagiert, wenn man in einem Thread keinen sleep drin hat. Ich finde das auch nicht glücklich und hätte auch nicht erwartet, daß das so ist - habe ich aber genau so erlebt. 

Das "keine Zeit abgegeben" stimmt in der Tat nicht und hatte ich auch so nicht gemeint - "wenig Zeit" wäre korrekt. Selbstverständlich werden auch die anderen Threads noch ausgeführt, aber z.B. ein Remote-Debugger reagiert plötzlich sehr zäh.

Die Threads, die ich damit meine, sind als InnerClass geschrieben worden und leiten von Thread ab. Könnte das falsch sein?


----------



## quippy (17. Mrz 2008)

Anonymous hat gesagt.:
			
		

> Habs jetzt so wie hier beschrieben implementiert und auch ein paar Sleeps eingebaut.
> 
> Bekomme aber immer noch folgende Exception:
> 
> ...



Könnte es sein, daß Du viele Objekte erzeugst? Arbeitest Du vielleicht mit viel Rekursion?

Ich frage mich gerade, ob die Terminologie in Java auch "heap" und "far heap" ist oder ob mit dem heap space der der VM zur Verfügung stehende Hauptspeicher gemeint ist?

Du kannst übrigens mit VM-Parametern "-Xms1024m -Xmx1024m" den der VM zugeteilten Speicher erhöhen. (äh - google mal, welcher was macht... Hier wird minimum und maximum 1 Gig zugewiesen - nicht unbedingt optimal)


----------



## tfa (17. Mrz 2008)

quippy hat gesagt.:
			
		

> Meine Erfahrung (und es mag sein, daß ich da was falsch implementiert habe!) hat gezeigt, daß die VM sehr langsam reagiert, wenn man in einem Thread keinen sleep drin hat. Ich finde das auch nicht glücklich und hätte auch nicht erwartet, daß das so ist - habe ich aber genau so erlebt.
> 
> Das "keine Zeit abgegeben" stimmt in der Tat nicht und hatte ich auch so nicht gemeint - "wenig Zeit" wäre korrekt. Selbstverständlich werden auch die anderen Threads noch ausgeführt, aber z.B. ein Remote-Debugger reagiert plötzlich sehr zäh.


Ja, das ist richtig. Wenn ein Thread viel macht und die CPU belastet, wird natürlich alles träge (ein Java-Programm ohne Nebenläufigkeit hat ja schon mind. einen Thread).
Man kann aber auch durch Setzen der Thread-Priorität noch einiges optimieren.



			
				quippy hat gesagt.:
			
		

> Die Threads, die ich damit meine, sind als InnerClass geschrieben worden und leiten von Thread ab. Könnte das falsch sein?


Nein, wie die Threads implementiert werden ist egal.


----------



## quippy (17. Mrz 2008)

tfa hat gesagt.:
			
		

> Wenn ein Thread viel macht und die CPU belastet, wird natürlich alles träge (ein Java-Programm ohne Nebenläufigkeit hat ja schon mind. einen Thread).



Das ist ja das doofe - die CPU war nicht ausgelastet. Ein eingestreuter "Thread.sleep(1L);" (inklusive IntrruptException-Behandlung) hat dann diese "Belastung" relativiert.


----------



## Gast (17. Mrz 2008)

So läuft jetzt soweit.
Danke.
Aber eine Frage habe ich noch.

Wie kann ich denn meinen Java-Programm zum Beipiel eine maximale CPU Last zuteilen? Geht das überhaupt?


----------



## quippy (17. Mrz 2008)

Gast hat gesagt.:
			
		

> So läuft jetzt soweit.
> Danke.
> Aber eine Frage habe ich noch.
> 
> Wie kann ich denn meinen Java-Programm zum Beipiel eine maximale CPU Last zuteilen? Geht das überhaupt?



Das ginge IMHO nur über das Betriebsystem. 

Unter Linux/Unix könntest Du den "nice"-Level (select the level how nice you are ) einstellen, so daß der OS-Thread deines Programms weniger Aufmerksamkeit bekommt.

Unter Windows geht das über den Task-Manager (Lasche Prozesse -> Rechtsklick auf den javaw-Prozess, dann Priorität festlegen)


----------

