Threads

Adriano10

Bekanntes Mitglied
Java:
public class QuickSort {

    public static void sort(int[] numbers) {
        new QuickSort().quickSort(numbers, 0, numbers.length - 1);
    }

    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        if (leftIndex < rightIndex) {
            int pivotIndex = divide(numbers, leftIndex, rightIndex);
            quickSort(numbers, leftIndex, pivotIndex - 1);
            quickSort(numbers, pivotIndex + 1, rightIndex);
        }
    }

    /**
     * liefert den Index des Pivot-Elementes und ordnet das Array innerhalb
     * der angegebenen Indizes so um, dass alle Zahlen links vom Index
     * kleiner oder gleich und alle Zahlen rechts vom Index groesser
     * oder gleich dem Pivot-Element sind
     */
    protected int divide(int[] numbers, int leftIndex, int rightIndex) {
        int pivotIndex = choosePivotIndex(numbers, leftIndex, rightIndex);
        int pivotValue = numbers[pivotIndex];
        // das Pivot-Element kommt nach ganz rechts im Array
        swap(numbers, pivotIndex, rightIndex);
        int left = leftIndex - 1;
        int right = rightIndex;

        do {
            left++;
            while (left <= rightIndex && numbers[left] <= pivotValue)
                left++;
            right--;
            while (right >= leftIndex && numbers[right] >= pivotValue)
                right--;
            if (left < right) {
                swap(numbers, left, right);
            }
        } while (left < right);
        // platziere das Pivot-Element an seine korrekte Position
        if (left < rightIndex) {
            swap(numbers, left, rightIndex);
            return left;
        } else {
            return rightIndex;
        }
    }

    protected int choosePivotIndex(int[] numbers, int leftIndex, int rightIndex) {

        return (leftIndex + rightIndex) / 2;
    }

    protected void swap(int[] numbers, int index1, int index2) {
        if (index1 != index2) {
            int tmp = numbers[index1];
            numbers[index1] = numbers[index2];
            numbers[index2] = tmp;
        }
    }

}

public class QuickSortTest {
    public static void main(String[] args) {
        int[] numbers = {2, 3, 9, 33, -2, 4, 55, 66, -234};
        print(numbers);
        QuickSort.sort(numbers);
        print(numbers);
       
        int[] numbers2 = {2, 3, 9, 33, -2, 4, 55, 66, -234};
        print(numbers2);
        QuickSortThreaded.sort(numbers2);
        print(numbers2);
    }
   
    private static void print(int[] numbers) {
        for (int number : numbers) {
            System.out.print(number + " ");
        }
        System.out.println();
    }


}

public class QuickSortThreaded extends QuickSort{

    public static void sort(int[] numbers) {

        QuickSort.sort(numbers);
    }

    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
       
        super.quickSort(numbers, leftIndex, rightIndex);
    }


}

In der Hilfsmethode quickSort werden nacheinander der Bereich links vom Pivot-Element und der Bereich rechts vom PivotElement durch rekursiven Aufruf der Methode sortiert. Die beide Aktionen sind unabhängig voneinander. Wie kann ich sie durch die Verwendung von Threads parallelisieren?
 
K

kneitzel

Gast
Du hast schon richtig erkannt, dass die zwei quicksort Aufrufe unabhängig voneinander sind.

Liegt Dein Problem nun darin, dass Du nicht weißt, wie Du einem neuen Thread die Parameter übergeben kannst? Eine Idee, das hin zu bekommen, wäre z.B. eine Klasse die Runnable implementiert. Im Konstruktor übergibst Du die Paramter in die Instanz.

Das geht auch über anonyme Klassen, aber dazu musst Du dann die Variablen mit den Parametern final machen.

Beides findest Du unter https://stackoverflow.com/questions/877096/how-can-i-pass-a-parameter-to-a-java-thread

Am Ende musst Du sicher stellen, dass die Threads beendet sind. Dazu kannst Du auf den erstellten Threads jeweils ein join aufrufen.

Und du musst natürlich nicht zwei Threads starten. Einen Thread hast Du ja schon. Zwei Threads zu starten und dann sofort ein join auf einen Thread auszuführen bringt keinen Vorteil. Also wäre die Logik:
- Einen Thread erstellen für eine Seite.
- Andere Seite direktmachen.
- join auf gestarteten Thread aufrufen
 

Adriano10

Bekanntes Mitglied
Du hast schon richtig erkannt, dass die zwei quicksort Aufrufe unabhängig voneinander sind.

Liegt Dein Problem nun darin, dass Du nicht weißt, wie Du einem neuen Thread die Parameter übergeben kannst? Eine Idee, das hin zu bekommen, wäre z.B. eine Klasse die Runnable implementiert. Im Konstruktor übergibst Du die Paramter in die Instanz.

Das geht auch über anonyme Klassen, aber dazu musst Du dann die Variablen mit den Parametern final machen.

Beides findest Du unter https://stackoverflow.com/questions/877096/how-can-i-pass-a-parameter-to-a-java-thread

Am Ende musst Du sicher stellen, dass die Threads beendet sind. Dazu kannst Du auf den erstellten Threads jeweils ein join aufrufen.

Und du musst natürlich nicht zwei Threads starten. Einen Thread hast Du ja schon. Zwei Threads zu starten und dann sofort ein join auf einen Thread auszuführen bringt keinen Vorteil. Also wäre die Logik:
- Einen Thread erstellen für eine Seite.
- Andere Seite direktmachen.
- join auf gestarteten Thread aufrufen
ja so habe ich mit der Implementierung von Runnable angefangen, danke für die Hinweise, ich versuche mal, ob ich die Methode run() zum Laufen bekomme.
 

Adriano10

Bekanntes Mitglied
Du hast schon richtig erkannt, dass die zwei quicksort Aufrufe unabhängig voneinander sind.

Liegt Dein Problem nun darin, dass Du nicht weißt, wie Du einem neuen Thread die Parameter übergeben kannst? Eine Idee, das hin zu bekommen, wäre z.B. eine Klasse die Runnable implementiert. Im Konstruktor übergibst Du die Paramter in die Instanz.

Das geht auch über anonyme Klassen, aber dazu musst Du dann die Variablen mit den Parametern final machen.

Beides findest Du unter https://stackoverflow.com/questions/877096/how-can-i-pass-a-parameter-to-a-java-thread

Am Ende musst Du sicher stellen, dass die Threads beendet sind. Dazu kannst Du auf den erstellten Threads jeweils ein join aufrufen.

Und du musst natürlich nicht zwei Threads starten. Einen Thread hast Du ja schon. Zwei Threads zu starten und dann sofort ein join auf einen Thread auszuführen bringt keinen Vorteil. Also wäre die Logik:
- Einen Thread erstellen für eine Seite.
- Andere Seite direktmachen.
- join auf gestarteten Thread aufrufen
Java:
public class QuickSortThreaded extends QuickSort implements Runnable{
    
    /**
     * sortiert das uebergebene Array in aufsteigender Reihenfolge
     * gemaess dem QuickSort-Algorithmus (parallel!)
     */
    
    private int[] number;
    int start, end;
    QuickSortThreaded(int[] number, int start, int end){
        this.number = number;
        this.start = start;
        this.end = end;
    }
    public static void sort(int[] numbers) {
        //TODO implement this
        QuickSort.sort(numbers);
    }

    /**
     * der Quicksort-Algorithmus wird auf dem Array zwischen den
     * angegebenen Indizes ausgefuehrt
     */
    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        
        super.quickSort(numbers, leftIndex, rightIndex);
    }

    @Override
    public void run() {
        quickSort(number, start, end);
        
    }


}

Das wollte ich Ihnen zeigen, ob ich auf dem richtigen Weg stehe.
 

Adriano10

Bekanntes Mitglied
Du hast schon richtig erkannt, dass die zwei quicksort Aufrufe unabhängig voneinander sind.

Liegt Dein Problem nun darin, dass Du nicht weißt, wie Du einem neuen Thread die Parameter übergeben kannst? Eine Idee, das hin zu bekommen, wäre z.B. eine Klasse die Runnable implementiert. Im Konstruktor übergibst Du die Paramter in die Instanz.

Das geht auch über anonyme Klassen, aber dazu musst Du dann die Variablen mit den Parametern final machen.

Beides findest Du unter https://stackoverflow.com/questions/877096/how-can-i-pass-a-parameter-to-a-java-thread

Am Ende musst Du sicher stellen, dass die Threads beendet sind. Dazu kannst Du auf den erstellten Threads jeweils ein join aufrufen.

Und du musst natürlich nicht zwei Threads starten. Einen Thread hast Du ja schon. Zwei Threads zu starten und dann sofort ein join auf einen Thread auszuführen bringt keinen Vorteil. Also wäre die Logik:
- Einen Thread erstellen für eine Seite.
- Andere Seite direktmachen.
- join auf gestarteten Thread aufrufen

Java:
public class QuickSortTest {
    public static void main(String[] args) {
    /*    int[] numbers = {2, 3, 9, 33, -2, 4, 55, 66, -234};
        print(numbers);
        QuickSort.sort(numbers);
        print(numbers);*/
        
        int[] numbers2 = {2, 3, 9, 33, -2, 4, 55, 66, -234};
    //    QuickSortThreaded.sort(numbers2);
        
        Thread thread = new Thread(new QuickSortThreaded(numbers2, 0, numbers2.length - 1));
        Thread thread1 = new Thread(new QuickSortThreaded(numbers2, 0, numbers2.length - 1));
        
        thread.start();
        thread1.start();
        
        try {
            thread.join();
            thread1.join();
        }catch(InterruptedException e) {
            
        }
        
        print(numbers2);
        
        
    }
    
    private static void print(int[] numbers) {
        for (int number : numbers) {
            System.out.print(number + " ");
        }
        System.out.println();
    }


}

public class QuickSortThreaded extends QuickSort implements Runnable{
    
    /**
     * sortiert das uebergebene Array in aufsteigender Reihenfolge
     * gemaess dem QuickSort-Algorithmus (parallel!)
     */
    

    private int[] numbers;
    //private int start, end;
    QuickSortThreaded(int[] numbers, int start, int end){
        this.numbers = numbers;
        quickSort(this.numbers, start, end);
        
        
    }
    public static void sort(int[] numbers) {
        //TODO implement this
        QuickSort.sort(numbers);
    }

    /**
     * der Quicksort-Algorithmus wird auf dem Array zwischen den
     * angegebenen Indizes ausgefuehrt
     */
    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        
        super.quickSort(numbers, leftIndex, rightIndex);
    }

    @Override
    public void run() {
        quickSort(numbers, 0, numbers.length - 1);
        
    }


}

so sieh mein Quelcode aus, zwar Array wird sortiert auf der Console sortiert ausgegeben, aber ich weiß trotzdem nicht, ob ich alles richtig gemacht habe.
 
K

kneitzel

Gast
Du bist zu schnell mit Deinen Posts ... ich war gerade noch dabei, zu deinem vorletzten Thread was zu schreiben :)

Da sah Dein Ansatz noch sehr gut aus. Du hattest da noch quickSort in der Oberklasse aufgerufen. Da hätte nur Deine eigene Implementation rein gemusst.

Und der Konstruktor ruft kein quickSort auf, denn so machst Du ja direkt im Hauptthread die Sortierung. Da wirklich nur die Parameter speichern für die spätere Verwendung!

Und in main erstellst Du keine Threads.

Also im run (oder wenn Du da nur ein quickSort aufrufen willst, in der quickSort methode) musst Du halt das implementieren, was Du in der Super Klasse schon hattest. Ich würde Dir raten, einfach einmal die quickSort Methode der Oberklasse 1:1 zu kopieren.
Und nur bei den rekursiven Aufrufen veränderst Du dann den Code, so dass Du Threads erstellst.

Dabei kannst Du Dir aber überlegen, nur einen Thread zu erstellen und beim zweiten den quickSort Aufruf so zu lassen.

Bildlich ausgedrückt: Es müssen zwei Dinge gemacht werden. Ohne zusätzliche Arbeiter bist Du der Arbeiter, der das machen muss, also machst du erst das Erste und danach das Zweite.

Mit den zusätzlichen Arbeitern ist die Logik derzeit:
Du erstellst zwei Arbeiter und schickst diese los. Du selbst (Bist ja auch ein Arbeiter) wartest, bis die zurück sind (join Aufrufe).

Aber Da Du zwe Sachen hast, ein Arbeiter hast Du schon, der auf das fertig werden warten soll, brauchst Du nur noch einen Arbeiter. Du musst also nur einen Arbeiter erstellen und los schicken und dann kannst Du selbst los rennen. Wenn Du zurück bist, musst Du nur auf den anderen Arbeiter warten und bist durch.
 

Adriano10

Bekanntes Mitglied
Du bist zu schnell mit Deinen Posts ... ich war gerade noch dabei, zu deinem vorletzten Thread was zu schreiben :)

Da sah Dein Ansatz noch sehr gut aus. Du hattest da noch quickSort in der Oberklasse aufgerufen. Da hätte nur Deine eigene Implementation rein gemusst.

Und der Konstruktor ruft kein quickSort auf, denn so machst Du ja direkt im Hauptthread die Sortierung. Da wirklich nur die Parameter speichern für die spätere Verwendung!

Und in main erstellst Du keine Threads.

Also im run (oder wenn Du da nur ein quickSort aufrufen willst, in der quickSort methode) musst Du halt das implementieren, was Du in der Super Klasse schon hattest. Ich würde Dir raten, einfach einmal die quickSort Methode der Oberklasse 1:1 zu kopieren.
Und nur bei den rekursiven Aufrufen veränderst Du dann den Code, so dass Du Threads erstellst.

Dabei kannst Du Dir aber überlegen, nur einen Thread zu erstellen und beim zweiten den quickSort Aufruf so zu lassen.

Bildlich ausgedrückt: Es müssen zwei Dinge gemacht werden. Ohne zusätzliche Arbeiter bist Du der Arbeiter, der das machen muss, also machst du erst das Erste und danach das Zweite.

Mit den zusätzlichen Arbeitern ist die Logik derzeit:
Du erstellst zwei Arbeiter und schickst diese los. Du selbst (Bist ja auch ein Arbeiter) wartest, bis die zurück sind (join Aufrufe).

Aber Da Du zwe Sachen hast, ein Arbeiter hast Du schon, der auf das fertig werden warten soll, brauchst Du nur noch einen Arbeiter. Du musst also nur einen Arbeiter erstellen und los schicken und dann kannst Du selbst los rennen. Wenn Du zurück bist, musst Du nur auf den anderen Arbeiter warten und bist durch.
Das heist in der sort methode soll ich drei Array erstellen, aber da diese Klasse interface Runnable implementiert, muss ich auch methode run() irgendwie zum Laufen bekommen, die ich, wie es scheint, überhaupt nicht benötige.

Ohne Runnable zu implementieren oder die Superklasse Threads zu erben, kann man das parallelisieren.. ?

Code:
public static void sort(int[] numbers) {
        int pivotElement = numbers[numbers.length-1];
        int[] array = new int[0];
        int[] arr = new int[0];
        int[] tmp;

        for (int numb: numbers) {
            if(numb <= pivotElement)
            {
                tmp = new int[kleiner.length+1];
                int i;
                for ( i = 0 ; i < kleiner.length ; i++)
                {
                    tmp[i] = kleiner[i];
                }
                tmp[i] = numb;
                kleiner = tmp;
            }
            else
            {
                tmp = new int[groesser.length+1];
                int i;
                for (i = 0 ; i < groesser.length ; i++)
                {
                    tmp[i] = groesser[i];
                }
                tmp[i] = numb;
                groesser = tmp;
            }
        }
 

Adriano10

Bekanntes Mitglied
Du bist zu schnell mit Deinen Posts ... ich war gerade noch dabei, zu deinem vorletzten Thread was zu schreiben :)

Da sah Dein Ansatz noch sehr gut aus. Du hattest da noch quickSort in der Oberklasse aufgerufen. Da hätte nur Deine eigene Implementation rein gemusst.

Und der Konstruktor ruft kein quickSort auf, denn so machst Du ja direkt im Hauptthread die Sortierung. Da wirklich nur die Parameter speichern für die spätere Verwendung!

Und in main erstellst Du keine Threads.

Also im run (oder wenn Du da nur ein quickSort aufrufen willst, in der quickSort methode) musst Du halt das implementieren, was Du in der Super Klasse schon hattest. Ich würde Dir raten, einfach einmal die quickSort Methode der Oberklasse 1:1 zu kopieren.
Und nur bei den rekursiven Aufrufen veränderst Du dann den Code, so dass Du Threads erstellst.

Dabei kannst Du Dir aber überlegen, nur einen Thread zu erstellen und beim zweiten den quickSort Aufruf so zu lassen.

Bildlich ausgedrückt: Es müssen zwei Dinge gemacht werden. Ohne zusätzliche Arbeiter bist Du der Arbeiter, der das machen muss, also machst du erst das Erste und danach das Zweite.

Mit den zusätzlichen Arbeitern ist die Logik derzeit:
Du erstellst zwei Arbeiter und schickst diese los. Du selbst (Bist ja auch ein Arbeiter) wartest, bis die zurück sind (join Aufrufe).

Aber Da Du zwe Sachen hast, ein Arbeiter hast Du schon, der auf das fertig werden warten soll, brauchst Du nur noch einen Arbeiter. Du musst also nur einen Arbeiter erstellen und los schicken und dann kannst Du selbst los rennen. Wenn Du zurück bist, musst Du nur auf den anderen Arbeiter warten und bist durch.
Das heist in der sort methode soll ich drei Array erstellen, aber da diese Klasse interface Runnable implementiert, muss ich auch methode run() irgendwie zum Laufen bekommen, die ich, wie es scheint, überhaupt nicht benötige.

Ohne Runnable zu implementieren oder die Superklasse Threads zu erben, kann man das parallelisieren.. ?

Code:
public static void sort(int[] numbers) {
        int pivotElement = numbers[numbers.length-1];
        int[] array = new int[0];
        int[] arr = new int[0];
        int[] tmp;

        for (int numb: numbers) {
            if(numb <= pivotElement)
            {
                tmp = new int[array.length+1];
                int i;
                for ( i = 0 ; i < array ; i++)
                {
                    tmp[i] = array[i];
                }
                tmp[i] = numb;
                array = tmp;
            }
            else
            {
                tmp = new int[arr.length+1];
                int i;
                for (i = 0 ; i < arr.length ; i++)
                {
                    tmp[i] = arr[i];
                }
                tmp[i] = numb;
               arr = tmp;
            }
        }
 
K

kneitzel

Gast
Was ich hier noch erwähnen möchte:
Der Ansatz ist nur begrenzt gut. Denn Du erstellst sehr schnell sehr viele Threads. Der Computer kann diese aber nur begrenzt parallel ausführen. Daher wirst Du bei großer Anzahl an Elementen schnell in eine Situation kommen, wo die CPU vor allem zwischen Threads umschaltet aber die Threads kaum noch Zeit bekommen.

Daher macht es Sinn, da eine Lösung zu finden, die die Anzahl der Threads begrenzt. Also nur n Threads und wenn die voll sind, dann werden keine weiteren Threads mehr benutzt. Dazu kann man sich überlegen, wie man dies bauen könnte.

Es gibt dazu aber auch prinzipiell schon Lösungen. So Thread Themen finden sich oft unter dem Stichwort ThreadPool. Ein sehr interessanter Artikel könnte z.B. https://www.baeldung.com/thread-pool-java-and-guava sein - speziell der Abschnitt 3.4 ForkJoinPool.
 
K

kneitzel

Gast
Also Du scheinst Dich gerade voll zu verrennen. Daher einfach einmal die ganzen Schritte der Entwicklung Schritt für Schritt durchgeführt

Du hast doch ohne Threads einfach nur:
Code:
    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        if (leftIndex < rightIndex) {
            int pivotIndex = divide(numbers, leftIndex, rightIndex);
            quickSort(numbers, leftIndex, pivotIndex - 1);
            quickSort(numbers, pivotIndex + 1, rightIndex);
        }
    }

Die Idee, die Du jetzt hattest, war doch, dass Du die quickSort Aufrufe in Threads machst.

Also etwas in der Form:
Code:
    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        if (leftIndex < rightIndex) {
            int pivotIndex = divide(numbers, leftIndex, rightIndex);
            quickSortOnNewThread(numbers, leftIndex, pivotIndex - 1);
            quickSort(numbers, pivotIndex + 1, rightIndex);
            waitForThreadToFinish();
        }
    }

Wobei ich jetzt schon darauf geachtet habe, dass der aktuelle Thread auch weiter verwendet wird.

Das waitForThreadToFinish benötigt eine Referenz auf den Thread und wird über ein join() Aufruf gemacht, also haben wir etwas wie:

Code:
    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        if (leftIndex < rightIndex) {
            int pivotIndex = divide(numbers, leftIndex, rightIndex);
            Thread thread = quickSortOnNewThread(numbers, leftIndex, pivotIndex - 1);
            quickSort(numbers, pivotIndex + 1, rightIndex);
            thread.join();
        }
    }

Wie können wir einen Thread erstellen, der diesen quickSort Aufruf macht?
a) Wir erstellen eine neue Instanz von QuickSortThreaded mit Konstruktor-Aufruf (numbers, leftIndex, pivotIndex-1)
b) Wir erzeugen einen neuen Thread mit dieser Instanz und geben diesen Thread dann zurück.

Damit haben wir etwas wie:
Code:
protected Thread createQuickSortThread(int[] numbers, int leftIndex, int rightIndex) {
    return new Thread(new QuickSortThreaded(number, leftIndex, rightIndex));
}

Und natürlich speichert der Konstruktor nur die übergebenen Werte:
Code:
    QuickSortThreaded(int[] numbers, int start, int end){
        this.numbers = numbers;
        this.start = start;
        this.end = end;
}

Und die run Methode ruft nur das entsprechende quickSort auf:
Code:
public void run() {
    quickSort(numbers, start, end);
}

Die Erweiterung bezüglich der Maximierung der Thread-Anzahl wäre denn z.B. dass die Methode createQuickSortThread auch null zurück geben kann... Das wäre dann in etwa so:

Code:
protected Thread createQuickSortThread(int[] numbers, int leftIndex, int rightIndex) {
    if (canCreateNewThreads())
        return new Thread(new QuickSortThreaded(number, leftIndex, rightIndex));

    // Do work in current thread and return null
    quickSort(numbers, leftIndex, rightIndex);
    return null;
}

Und der join Aufruf braucht dann natürlich einen null check:
Code:
    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        if (leftIndex < rightIndex) {
            int pivotIndex = divide(numbers, leftIndex, rightIndex);
            Thread thread = quickSortOnNewThread(numbers, leftIndex, pivotIndex - 1);
            quickSort(numbers, pivotIndex + 1, rightIndex);
            if (thread != null) thread.join();
        }
    }
Wie dann canCreateNewThreads() implementiert wird, muss man überlegen. Man könnte z.B. einen Zähler einbauen und wenn der Zähler < Maximum ist, dann wird er eins hoch gezählt und true ausgegeben. Und ansonsten false. Und in der run methode könnte man am Ende noch den Zähler reduzieren. Der Zähler muss dabei so geschützt werden, dass immer nur ein Thread diesen verändern kann.... Das kann man ggf. aber auch noch optimieren, aber das lassen wir an der Stelle einfach erst einmal :)
 

Adriano10

Bekanntes Mitglied
Also Du scheinst Dich gerade voll zu verrennen. Daher einfach einmal die ganzen Schritte der Entwicklung Schritt für Schritt durchgeführt

Du hast doch ohne Threads einfach nur:
Code:
    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        if (leftIndex < rightIndex) {
            int pivotIndex = divide(numbers, leftIndex, rightIndex);
            quickSort(numbers, leftIndex, pivotIndex - 1);
            quickSort(numbers, pivotIndex + 1, rightIndex);
        }
    }

Die Idee, die Du jetzt hattest, war doch, dass Du die quickSort Aufrufe in Threads machst.

Also etwas in der Form:
Code:
    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        if (leftIndex < rightIndex) {
            int pivotIndex = divide(numbers, leftIndex, rightIndex);
            quickSortOnNewThread(numbers, leftIndex, pivotIndex - 1);
            quickSort(numbers, pivotIndex + 1, rightIndex);
            waitForThreadToFinish();
        }
    }

Wobei ich jetzt schon darauf geachtet habe, dass der aktuelle Thread auch weiter verwendet wird.

Das waitForThreadToFinish benötigt eine Referenz auf den Thread und wird über ein join() Aufruf gemacht, also haben wir etwas wie:

Code:
    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        if (leftIndex < rightIndex) {
            int pivotIndex = divide(numbers, leftIndex, rightIndex);
            Thread thread = quickSortOnNewThread(numbers, leftIndex, pivotIndex - 1);
            quickSort(numbers, pivotIndex + 1, rightIndex);
            thread.join();
        }
    }

Wie können wir einen Thread erstellen, der diesen quickSort Aufruf macht?
a) Wir erstellen eine neue Instanz von QuickSortThreaded mit Konstruktor-Aufruf (numbers, leftIndex, pivotIndex-1)
b) Wir erzeugen einen neuen Thread mit dieser Instanz und geben diesen Thread dann zurück.

Damit haben wir etwas wie:
Code:
protected Thread createQuickSortThread(int[] numbers, int leftIndex, int rightIndex) {
    return new Thread(new QuickSortThreaded(number, leftIndex, rightIndex));
}

Und natürlich speichert der Konstruktor nur die übergebenen Werte:
Code:
    QuickSortThreaded(int[] numbers, int start, int end){
        this.numbers = numbers;
        this.start = start;
        this.end = end;
}

Und die run Methode ruft nur das entsprechende quickSort auf:
Code:
public void run() {
    quickSort(numbers, start, end);
}

Die Erweiterung bezüglich der Maximierung der Thread-Anzahl wäre denn z.B. dass die Methode createQuickSortThread auch null zurück geben kann... Das wäre dann in etwa so:

Code:
protected Thread createQuickSortThread(int[] numbers, int leftIndex, int rightIndex) {
    if (canCreateNewThreads())
        return new Thread(new QuickSortThreaded(number, leftIndex, rightIndex));

    // Do work in current thread and return null
    quickSort(numbers, leftIndex, rightIndex);
    return null;
}

Und der join Aufruf braucht dann natürlich einen null check:
Code:
    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        if (leftIndex < rightIndex) {
            int pivotIndex = divide(numbers, leftIndex, rightIndex);
            Thread thread = quickSortOnNewThread(numbers, leftIndex, pivotIndex - 1);
            quickSort(numbers, pivotIndex + 1, rightIndex);
            if (thread != null) thread.join();
        }
    }
Wie dann canCreateNewThreads() implementiert wird, muss man überlegen. Man könnte z.B. einen Zähler einbauen und wenn der Zähler < Maximum ist, dann wird er eins hoch gezählt und true ausgegeben. Und ansonsten false. Und in der run methode könnte man am Ende noch den Zähler reduzieren. Der Zähler muss dabei so geschützt werden, dass immer nur ein Thread diesen verändern kann.... Das kann man ggf. aber auch noch optimieren, aber das lassen wir an der Stelle einfach erst einmal :)
super danke... voll verständlich...
 

Adriano10

Bekanntes Mitglied
Also Du scheinst Dich gerade voll zu verrennen. Daher einfach einmal die ganzen Schritte der Entwicklung Schritt für Schritt durchgeführt

Du hast doch ohne Threads einfach nur:
Code:
    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        if (leftIndex < rightIndex) {
            int pivotIndex = divide(numbers, leftIndex, rightIndex);
            quickSort(numbers, leftIndex, pivotIndex - 1);
            quickSort(numbers, pivotIndex + 1, rightIndex);
        }
    }

Die Idee, die Du jetzt hattest, war doch, dass Du die quickSort Aufrufe in Threads machst.

Also etwas in der Form:
Code:
    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        if (leftIndex < rightIndex) {
            int pivotIndex = divide(numbers, leftIndex, rightIndex);
            quickSortOnNewThread(numbers, leftIndex, pivotIndex - 1);
            quickSort(numbers, pivotIndex + 1, rightIndex);
            waitForThreadToFinish();
        }
    }

Wobei ich jetzt schon darauf geachtet habe, dass der aktuelle Thread auch weiter verwendet wird.

Das waitForThreadToFinish benötigt eine Referenz auf den Thread und wird über ein join() Aufruf gemacht, also haben wir etwas wie:

Code:
    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        if (leftIndex < rightIndex) {
            int pivotIndex = divide(numbers, leftIndex, rightIndex);
            Thread thread = quickSortOnNewThread(numbers, leftIndex, pivotIndex - 1);
            quickSort(numbers, pivotIndex + 1, rightIndex);
            thread.join();
        }
    }

Wie können wir einen Thread erstellen, der diesen quickSort Aufruf macht?
a) Wir erstellen eine neue Instanz von QuickSortThreaded mit Konstruktor-Aufruf (numbers, leftIndex, pivotIndex-1)
b) Wir erzeugen einen neuen Thread mit dieser Instanz und geben diesen Thread dann zurück.

Damit haben wir etwas wie:
Code:
protected Thread createQuickSortThread(int[] numbers, int leftIndex, int rightIndex) {
    return new Thread(new QuickSortThreaded(number, leftIndex, rightIndex));
}

Und natürlich speichert der Konstruktor nur die übergebenen Werte:
Code:
    QuickSortThreaded(int[] numbers, int start, int end){
        this.numbers = numbers;
        this.start = start;
        this.end = end;
}

Und die run Methode ruft nur das entsprechende quickSort auf:
Code:
public void run() {
    quickSort(numbers, start, end);
}

Die Erweiterung bezüglich der Maximierung der Thread-Anzahl wäre denn z.B. dass die Methode createQuickSortThread auch null zurück geben kann... Das wäre dann in etwa so:

Code:
protected Thread createQuickSortThread(int[] numbers, int leftIndex, int rightIndex) {
    if (canCreateNewThreads())
        return new Thread(new QuickSortThreaded(number, leftIndex, rightIndex));

    // Do work in current thread and return null
    quickSort(numbers, leftIndex, rightIndex);
    return null;
}

Und der join Aufruf braucht dann natürlich einen null check:
Code:
    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        if (leftIndex < rightIndex) {
            int pivotIndex = divide(numbers, leftIndex, rightIndex);
            Thread thread = quickSortOnNewThread(numbers, leftIndex, pivotIndex - 1);
            quickSort(numbers, pivotIndex + 1, rightIndex);
            if (thread != null) thread.join();
        }
    }
Wie dann canCreateNewThreads() implementiert wird, muss man überlegen. Man könnte z.B. einen Zähler einbauen und wenn der Zähler < Maximum ist, dann wird er eins hoch gezählt und true ausgegeben. Und ansonsten false. Und in der run methode könnte man am Ende noch den Zähler reduzieren. Der Zähler muss dabei so geschützt werden, dass immer nur ein Thread diesen verändern kann.... Das kann man ggf. aber auch noch optimieren, aber das lassen wir an der Stelle einfach erst einmal :)
Java:
public class QuickSortThreaded extends QuickSort implements Runnable{
    
    private  int[] numbers;

    
    QuickSortThreaded(int[] numbers){
        this.numbers = numbers;
    }

    public static void sort(int[] numbers) {
        QuickSort.sort(numbers);
    }

    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        
        super.quickSort(numbers, leftIndex, rightIndex);
        
    }

    @Override
    public void run() {
        int pivot = divide(numbers, 0, numbers.length - 1);
        
        Thread thread = new Thread(() -> quickSort(numbers, 0, pivot - 1));
        Thread thread1 = new Thread(() -> quickSort(numbers, pivot + 1, numbers.length - 1));
        thread.start();
        thread1.start();
        
        try {
            thread.join();
            thread1.join();
        }catch(InterruptedException e) {
            
        }        }
}


public class QuickSortTest {

    public static void main(String[] args) {
        int[] numbers = {2, 3, 9, 33, -2, 4, 55, 66, -234};
        print(numbers);
        QuickSort.sort(numbers);
        print(numbers);
        
        int[] numbers2 = {2, 3, 9, 33, -2, 4, 55, 66, -234};
        print(numbers2);
        QuickSortThreaded q = new QuickSortThreaded(numbers2);
        q.run();
        print(numbers2);
    }
    
    private static void print(int[] numbers) {
        for (int number : numbers) {
            System.out.print(number + " ");
        }
        System.out.println();
    }

}

Jetzt muss sie funktionieren... Ich hab echt viel Mühe gegeben, da diese Threads, wie eben gesaget habe, mir ganzu neu sind.
 
K

kneitzel

Gast
Sorry, aber Ziel soll doch sein, dass das quickSort nun mit Threads arbeitet.

Also ist sowas
Code:
    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        super.quickSort(numbers, leftIndex, rightIndex);
    }
bestimmt nicht korrekt. Es sei denn, du willst nur einmalig zwei Threads haben und die dann wie normal durchlaufen lassen....

Code:
        QuickSortThreaded q = new QuickSortThreaded(numbers2);
        q.run();
das führt das Runnable ad absurdum. Der Sinn dahinter ist doch gerade, dass da ein anderer Thread das ausführt. so ein run() Aufruf ist in der Regel immer sehr dubios.

Code:
    public static void sort(int[] numbers) {
        QuickSort.sort(numbers);
    }
Das ist noch alter Müll? Der sort Aufruf in der neuen Klasse soll einfach sort von QuickSort aufrufen? Also keine Threads und so? Das wirst Du doch nicht wollen, oder?

Dann führst Du plötzlich Lambdas ein. Ist ok, kann man machen. Dann brauchst Du aber kein Runnable mehr....

Code:
public class QuickSortThreaded extends QuickSort {
   
    public static void sort(int[] numbers) {
        new QuickSortThreaded().quickSort(numbers, 0, numbers.length - 1);
    }

    protected void quickSort(int[] numbers, int leftIndex, int rightIndex) {
        if (leftIndex >= rightIndex) return;
       
        int pivot = divide(numbers, leftIndex, rightIndex);
       
        Thread thread = new Thread(() -> quickSort(numbers, leftIndex, pivot - 1));
        thread.start();
        quickSort(numbers, pivot + 1, rightIndex);

        try {
            thread.join();
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Das einfach mal im Forum-Editor zusammen geschrieben als kurze, prägnante Lösung.

Und nutzen kannst Du das so, wie auch die QuickSort Klasse - durch Aufruf der statischen sort Methode.

Edit: Musste natürlich new QuickSortThreaded() in sort() sein!
 
K

kneitzel

Gast
Ich habe jetzt einmal ein GitHub repo gestartet mit Algorithmen für das Forum. Da habe ich dann mal jeweils die Implementation rein getan, wie ich diese geschrieben hätte.

Pivot Element ist bei mir einfach das rechte Element, dadurch kein Tausch nach Rechts und so ... (So aufgebaut wir bei Wikipedia auch beschrieben)

GitHub Repository findet man unter: https://github.com/kneitzel/java-forum-algorithms

Feedback und Verbesserungsvorschläge nehme ich gerne entgegen :)
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
H Nutzt Eclipse alle CPU-Threads beim Ausführen von Java-Programmen? Java Basics - Anfänger-Themen 4
C Threads und Swing Java Basics - Anfänger-Themen 9
berserkerdq2 Wo finde ich in der Java Api die Notation zu Threads bezüglich Synchronized? Java Basics - Anfänger-Themen 14
berserkerdq2 Findet eine parallele Verarbeitung in Java bei Threads erst statt, wenn man die Methoden auch synchronized? Und wie sieht bei Conditions aus? Java Basics - Anfänger-Themen 8
B Monitor als Schranke von Threads Java Basics - Anfänger-Themen 20
W Threads Alphabet Java Basics - Anfänger-Themen 20
H Threads Anfänger Java Basics - Anfänger-Themen 17
1 Threads parallel laufen Java Basics - Anfänger-Themen 11
B Threads Problem mit mehreren Threads Java Basics - Anfänger-Themen 38
M Threads Java Basics - Anfänger-Themen 12
L Threads Synchronisierung zwischen threads Java Basics - Anfänger-Themen 4
M Threads Java Basics - Anfänger-Themen 2
A Threads Java Basics - Anfänger-Themen 9
A Threads und .join Java Basics - Anfänger-Themen 14
W Threads starten Java Basics - Anfänger-Themen 2
X Threads Zwei Threads, aber doppelte Ausgabe verhindern (synchronized) Java Basics - Anfänger-Themen 54
J Wieviele threads? Java Basics - Anfänger-Themen 9
J Problem bei seriellem Start von Threads Java Basics - Anfänger-Themen 11
O Threads Java Basics - Anfänger-Themen 2
L Buchungssystem und Threads Java Basics - Anfänger-Themen 2
O Threads - Synchronize(), join(), wait(), notify(), yield() Java Basics - Anfänger-Themen 6
L Klassen NFC Reader und JavaFx Problem -> threads? Java Basics - Anfänger-Themen 2
A Kommunikation zwischen nebenläufigen Threads Java Basics - Anfänger-Themen 4
S Gemeinsame Ressource und Mehrfachinstanziierung von Threads Java Basics - Anfänger-Themen 16
S Verklemmung Threads Java Basics - Anfänger-Themen 11
B Threads 2 Threads gleichzeitig laufen lassen Java Basics - Anfänger-Themen 1
M Threads Threads laufen sequenziell, statt gleichzeitig. Java Basics - Anfänger-Themen 9
M Threads run Methode Java Basics - Anfänger-Themen 4
javajoshi mehrere Threads: Methoden zentral unterbringen Java Basics - Anfänger-Themen 8
javajoshi Problem mit zwei Threads und Arrays (Runnable) Java Basics - Anfänger-Themen 12
L Threads Mit Threads JLabel ändern! Java Basics - Anfänger-Themen 2
K Matrixen berechnen nach Worker Master Paradigma mit Threads Java Basics - Anfänger-Themen 4
S Kleine Frage zu Threads Java Basics - Anfänger-Themen 3
M Mit 2 Threads eine Zahl hochzählen Java Basics - Anfänger-Themen 13
T Threads Synchronisieren Java Basics - Anfänger-Themen 6
D Frage Threads Java Basics - Anfänger-Themen 6
Z Threads Executor Framework - Aufgabe auf n Threads aufteilen Java Basics - Anfänger-Themen 10
Z Threads Threads - Zugriff auf Ressourcen ohne(Lock, Synchronized) Java Basics - Anfänger-Themen 2
kilopack15 Verständnisfrage zur Verwendung von notify() bei Threads Java Basics - Anfänger-Themen 2
kilopack15 Mehrere Threads in einer Klasse Java Basics - Anfänger-Themen 8
H Threads funktionieren nicht Java Basics - Anfänger-Themen 4
J Aufgabe(Threads) richtig verstanden/implementiert Java Basics - Anfänger-Themen 27
R Threads aufeinander warten lassen? Java Basics - Anfänger-Themen 10
T Threads Durch threads gestartete Prozesse killen Java Basics - Anfänger-Themen 2
J Threads Java Basics - Anfänger-Themen 38
D Alte Klausuraufgabe Threads Java Basics - Anfänger-Themen 10
A Threads Threads bestimmte Aufgaben zuweisen... Java Basics - Anfänger-Themen 3
R Threads in JavaFX Java Basics - Anfänger-Themen 3
E Threads Doppelte Threads beenden Java Basics - Anfänger-Themen 4
F Sicheres Zurückmelden aus Threads Java Basics - Anfänger-Themen 0
G Threads zum Thema Threads??? null Ahnung Java Basics - Anfänger-Themen 4
Q Threads Threads in Swing Anwendungen Java Basics - Anfänger-Themen 5
J ConcurrentCalculation Multi Threads in Java Java Basics - Anfänger-Themen 3
P Threads Trotz Threads wird nur 1 Prozessorkern ausgelastet Java Basics - Anfänger-Themen 7
M "restartable" threads Java Basics - Anfänger-Themen 11
M Threads - summieren Java Basics - Anfänger-Themen 13
W Klassen Variable einer anderen Klasse ändern (Threads) Java Basics - Anfänger-Themen 3
E Threads - Programm analysieren Java Basics - Anfänger-Themen 2
E join() bei zwei Threads Java Basics - Anfänger-Themen 2
T Threads Threads richtig synchronisieren Java Basics - Anfänger-Themen 3
D [Concurrency/Threads] Code Umsetzung Schriftlich Java Basics - Anfänger-Themen 2
D Threads Java Basics - Anfänger-Themen 4
M Threads nio Dateien kopieren, Threads und Gui Java Basics - Anfänger-Themen 0
N Verweise auf Variablen in verschiedenen Threads Java Basics - Anfänger-Themen 4
T Java-Threads Java Basics - Anfänger-Themen 0
G Moving Objects with Threads (implements Runnable) Java Basics - Anfänger-Themen 1
F Threads funktionieren auf JPanel nicht Java Basics - Anfänger-Themen 1
M Problem mit Threads Java Basics - Anfänger-Themen 11
M Threads - wo gehören sie hin? Java Basics - Anfänger-Themen 3
S 2D-Spiel mit Threads... Java Basics - Anfänger-Themen 3
J Threads Java Basics - Anfänger-Themen 3
F ExecutorService und offene Threads Java Basics - Anfänger-Themen 3
P Threads Threads nicht nebenläufig Java Basics - Anfänger-Themen 7
M Threads nicht nebenleblaufig Java Basics - Anfänger-Themen 2
B Threads parallel zur main Java Basics - Anfänger-Themen 3
M Threads Java Basics - Anfänger-Themen 2
M Threads, zwei methoden gleichzeitig laufen lassen Java Basics - Anfänger-Themen 4
M Threads und Methodenübergreifender Variablezugriff Java Basics - Anfänger-Themen 2
J Wie handle ich Threads am besten? Java Basics - Anfänger-Themen 2
H Threads Java Basics - Anfänger-Themen 10
B synchronized threads Java Basics - Anfänger-Themen 17
E Mehrmaliges Ausführen eines Threads Java Basics - Anfänger-Themen 5
E Threads Verständnisfrage bzgl. Threads und Sleep Java Basics - Anfänger-Themen 2
T Alle Threads .notify() Java Basics - Anfänger-Themen 13
R Threads Verständnisschwierigkeit Java Basics - Anfänger-Themen 2
J Können mehere Threads parallel eine Datei lesen? Java Basics - Anfänger-Themen 4
G Methoden in Threads wandeln Java Basics - Anfänger-Themen 7
H Threads Java Basics - Anfänger-Themen 17
F Java Concurrency - Threads Java Basics - Anfänger-Themen 4
V Threads Threads synchronisieren Java Basics - Anfänger-Themen 4
T Threads Join() = Block? oO Java Basics - Anfänger-Themen 4
J Threads ArrayList Problem bei Threads Java Basics - Anfänger-Themen 3
C Objekte durchschleifen / Threads Java Basics - Anfänger-Themen 2
J Threads stoppen mit interrupt - Frage dazu Java Basics - Anfänger-Themen 7
N Pingen in Threads Java Basics - Anfänger-Themen 9
B Threads benutzen Java Basics - Anfänger-Themen 5
E Allgemein Verständnissfrage zum Ablauf mehrerer Threads Java Basics - Anfänger-Themen 4
S Threads erzeugen Java Basics - Anfänger-Themen 11
K Threads Nur 2 von 3 Threads funktionieren Java Basics - Anfänger-Themen 8
P Threads Methode von Threads erledigen lassen Java Basics - Anfänger-Themen 11

Ähnliche Java Themen

Neue Themen


Oben