MultiThreading.. Scheduling-Problem?

akimoon

Aktives Mitglied
Hi,

ich hätte ein Problem bezüglich Multithreading. Und zwar erstelle ich 3 Threads, welche "parallel" zur main-Methode abgearbeitet werden sollen. Hierbei tritt nun allerdings das Problem auf, dass scheinbar nur der main-Thread abgearbeitet wird? Ausgegeben wird:
"Main läuft..."
"Main läuft..."
"Main läuft..."
"Main läuft..."
"Main läuft..."

... Soweit ich bisher Multithreading verstanden hatte, sollte der Prozessor zwischen den Threads in Abständen wechseln und somit auch mal "Mein Thread startet..." etc ausgegeben werden, oder hab ich da was falsch verstanden?


Programmstart:
Java:
public class Programmstart {
    public static void main(String[] args) {
        MeinThread t = new MeinThread();
        t.start();

        MeinThread2 t2 = new MeinThread2();
        t2.start();

        Thread r = new Thread(new MeinZweiterThread());
        r.start();

        while(true){
            System.out.println("Main läuft...");
        }
    }
}

MeinThread:
Java:
public class MeinThread extends Thread{

    @Override
    public void run() {
        System.out.println("Mein Thread start.... :-)");
        while(true){
            System.out.println("Mein Thread läuft.... :-)");
        }
    }
}

MeinZweiterThread:
Java:
public class MeinZweiterThread implements Runnable{
    public void run() {
        while(true){
            System.out.println("Mein Runnable läuft....");
        }
    }
}

MeinThread2:
Java:
public class MeinThread2 extends Thread{

    @Override
    public void run() {
        System.out.println("Mein Thread2 start.... :-)");
        while(true){
            System.out.println("Mein Thread2 läuft.... :-)");
        }
    }
}
 
Pack mal ein paar Thread.sleep(1000) in die Schleife mit rein...

Ich denke mal du siehst die anderen Outputs einfach nicht.
 
ein Thread kann nur laufen wenn er Zeit dafür bekommt. Wenn dein Main Thread immer 100% der CPU in Anspruch nimmt, wird nie ein anderer Thread vom Scheduler Zeit bekommen. Bau mal ein Thread.yield(); in den Threads ein.
 
Wenn man das so laufen lässt wird die anderen threads auch zwischendurch immer wieder CPU Zeit gegeben. Zumindest bei mir 😉

Java:
import java.util.Random;

public class Programmstart {
    public static void main(String[] args) {
        MeinThread t = new MeinThread();
        t.start();
 
        MeinThread2 t2 = new MeinThread2();
        t2.start();
 
        Thread r = new Thread(new MeinZweiterThread());
        r.start();
 
        Random rnd = new Random();
        while(true){
        	try {
				Thread.sleep(rnd.nextInt(1000)+1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            System.out.println("Main läuft...");
        }
    }
}

class MeinThread2 extends Thread{
	 
    @Override
    public void run() {
        Random rnd = new Random();
        System.out.println("Mein Thread2 start.... :-)");
        while(true){
        	try {
				Thread.sleep(rnd.nextInt(1000)+1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            System.out.println("Mein Thread2 läuft.... :-)");
        }
    }
}

class MeinZweiterThread implements Runnable{
    public void run() {
    	Random rnd = new Random();
        while(true){
        	try {
				Thread.sleep(rnd.nextInt(1000)+1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            System.out.println("Mein Runnable läuft....");
        }
    }
}

class MeinThread extends Thread{
	 
    @Override
    public void run() {
    	Random rnd = new Random();
        System.out.println("Mein Thread start.... :-)");
        while(true){
        	try {
				Thread.sleep(rnd.nextInt(1000)+1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            System.out.println("Mein Thread läuft.... :-)");
        }
    }
}
 
Ja, so sollte es eigentlich sein. Kann dein Problem nicht wirklich nachvollziehen, so funktioniert es jedenfalls bei mir problemlos:

Java:
public class ThreadTest {

	public static void main(String[] args) {
        MeinThread t = new ThreadTest().new MeinThread();
        t.start();
 
        while(true){
            System.out.println("Main läuft...");
        }
    }

	public class MeinThread extends Thread {
		@Override
		public void run() {
			System.out.println("Mein Thread start.... :-)");
			while(true){
				System.out.println("Mein Thread läuft.... :-)");
			}
		}
	}
}
 
Niki: Also mit yield() funktioniert es, danke 🙂 Kannst du mir das eventuell auch noch erklären? Komisch ist, wenn ich in der main()-Methode das system.out.println("...") wegnehm, wird auch "Mein Thread läuft... 🙂" ausgegeben.


Fassy: Bei deinem Code erscheint bei mir nur folgendes auf der Konsole:
Code:
Mein Thread start.... :-)
Mein Thread läuft.... :-)
Mein Thread läuft.... :-)
Mein Thread läuft.... :-)
....

megalomaniac: Das ist ja auch mein Problem, dass es eigentlich funktioneiren sollte =/
Das ganze stammt eigentlich aus einem online-Tutorial..:
YouTube - Java Tutorial - Vom Noob zum SCJP! Teil 30: Multi-Threading Java Tutorial - Vom Noob zum SCJP! Teil 30: Multi-Threading
 
ein Thread kann nur laufen wenn er Zeit dafür bekommt. Wenn dein Main Thread immer 100% der CPU in Anspruch nimmt, wird nie ein anderer Thread vom Scheduler Zeit bekommen. Bau mal ein Thread.yield(); in den Threads ein.
nana, so schlimm ist es auch nicht,
bevor die anderen Threads drankommen, ja überhaupt gestartet sind, kann main in wenigen Millisekunden genug Ausgaben absetzen, um jede Konsole für längere Zeit mit der Anzeige zu beschäftigen,
ob yield() oder nicht ('kann' im Sinne von kann, dass yield() hier hilft habe ich auch grad gelesen),

aber generell kann ein Thread nicht die ganze CPU belegen, es findet alle paar Millisekunden automatisch ein Wechsel statt
 
aber generell kann ein Thread nicht die ganze CPU belegen, es findet alle paar Millisekunden automatisch ein Wechsel statt

ich bin mir da nicht 100% sicher ob das so ist (könnte glaub ich auch VM abhängig sein). meiner meinung nach sollte man trotzdem immer im thread selber anderen threads zeit geben auch mal dran zu kommen. Thread.yield(); macht genau das (doku lesen).

//EDIT
hab ein wenig nachgelesen, das könnte das Verhalten erklären:

Thread Scheduling

Siehe Time Slicing
 
Zuletzt bearbeitet:
ein löbliches Kommando, ohne Frage, nur im Standard quasi nicht betrachtet,
da kannst du dir alle einfachen Threads im Internet anschauen,

etwa
Galileo Computing :: Java ist auch eine Insel (8. Auflage) – 11.2 Threads erzeugen
das erste Beispiel mit DateCommand + CounterCommand,
läuft durcheinander, ohne yield(), wobei bei mir gerade nicht da eh so schnell,
da muss man schon bisschen mehr Berechnung einbauen

Java:
public class Test {
    public static void main(String[] args)  {
        Thread t1 = new Thread(new DateCommand());
        t1.start();
        Thread t2 = new Thread(new CounterCommand());
        t2.start();
    }
}
class DateCommand  implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++)   {
            System.out.println(new java.util.Date() + " - " + CounterCommand.calc());
        }
    }
}
class CounterCommand  implements Runnable {
    public static double calc()  {
        double x = 2;
        for (int k = 1; k < 3000000; k++)  {
            x += k;
        }
        return x;
    }
    @Override
    public void run()  {
        for (int i = 0; i < 20; i++)   {
            System.out.println(i + " - " + CounterCommand.calc());
        }
    }
}
oder man denke an nebenläuftige Berechnungen zum GUI-Zeichen-Thread

edit:
Your programs should not rely on time slicing because it can produce different results on different systems.
habe ich nun gelesen, ok, man sollte so vieles richtig machen 😉

edit:
auch interessant in der Java-Insel
static void yield()
Der laufende Thread gibt freiwillig seine Rechenzeit ab. Die Methode ist für Implementierungen der JVM nicht verbindlich.
 
Zuletzt bearbeitet von einem Moderator:
genau das mein ich. Threading ist generell Umgebungsabhängig. Statt Thread.yield(); kann man auch Thread.sleep(10); verwenden. Das sollte auch bewirken dass andere Threads dran kommen.
 

Zurück
Oben