Dein Java-Programm kann auch mehr Threads erzeugen, als das System Prozessoren hat.
Die Threads, die du erzeugst, werden dann vom Betriebssystem verwaltet (native Threads sind quasi Standard in modernen VMs) und den verfügbaren Prozessoren zugewiesen.
Wenn dein Thread also Arbeit hat (und nicht gerade auf eine Netzwerkverbindung oder andere Events wartet), werden deine Thread irgendwann einen Prozessor abbekommen. Das stellen die Scheduler in den Betriebssystemen eigentlich recht gut sicher.
Garantien für die Nebenläufigkeit der Threads gibt es aber keine. Deine 4 Threads könnten also sogar auf einem 16-Kern-System auf einem einzigen Kern zeitversetzt laufen (sonst könnte dein Programm ja auch gar nicht auf einem 1-Kern-System ausgeführt werden).
Die Java Concurrency API (
http://docs.oracle.com/javase/tutorial/essential/concurrency/) nimmt dir übrigens einiges ab, was die Verwaltung mehrerer Threads, deren Synchronisierung, die Synchronisierung von konkurrierenden Zugriffen, und die Verteilung von Arbeit angeht.
Im Code ein kleines Beispiel, das einen Pool an Threads in einem sog. "Executor" anlegt; diesem Executor werden dann Aufgaben zugewiesen und er kümmert sich selbst um die Verteilung auf die verfügbaren Threads (das Beispiel erzeugt nur so viele Threads, wie deine VM Prozessoren hat).
Code:
final int numberOfProcessors = Runtime.getRuntime().availableProcessors();
final ExecutorService executor = Executors.newFixedThreadPool(numberOfProcessors);
// Job ohne Rückgabewert
final Runnable command = new Runnable() {
@Override
public void run() {
someHeavyLifting();
}
};
executor.execute(command);
// Job mit Rückgabewert
final Callable<String> task = new Callable<String>() {
@Override
public String call() throws Exception {
return getStringFromSlowRemoteHost();
}
};
final Future<String> resultFuture = executor.submit(task);
// ...
// irgendwas anderes machen
// ...
resultFuture.get();