# Threads - Werte zwischen verschiedenen Threads übermitteln



## gta008 (10. Feb 2022)

Guten Tag,
ich schreibe gerade ein Programm, welches das Vorkommen des Wertes 3 in einem int Array zählen soll. Dies soll so erfolgen, dass ein Array der länge n (Eingabewert) mit Zufallszahlen gefüllt wird und dann das Vorkommen des Wertes 3 auf k (Eingabewert) Threads berechnet wird. Zusätzlich soll von einem weiteren Thread (PrintThread) immer wenn der counter sich um 100 erhöht hat eine Systemausgabe kommen sowie am Ende von diesem Thread das Gesamtergebnis. Mein Problem ist, dass ich nicht genau weiß, wie ich den Counter zwischen allen Threads "gleich" halte, sodass diese gegenseitig auf denselben Wert zugreifen und wie ich diesen dann an die PrintThread übergebe. 
[CODE lang="java" title="CountNumbers (main Methode)"]public class CountNumbers {

    public static void main(String[] args) {
        final int counter = 0;
        Scanner sc = new Scanner(System.in);
        System.out.print("Geben Sie n ein: ");
        int n = sc.nextInt();
        System.out.print("Geben Sie k ein: ");
        int k = sc.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; ++i) {
            a_ = (int) (Math.random() * 10);
        }
        for (int i = 0; i < k; ++i) {
            Thread CountThread = new CountThread(k, i, n, a);
            CountThread.start();
        }
    }
}[/CODE]

[CODE lang="java" title="CountThread"]public class CountThread extends Thread{

    int counter, k,i,n;
    int[] a;

    CountThread (int k, int i, int n, int[] a) {
        this.k = k;
        this.i = i;
        this.n = n;
        this.a = a;
    }

    public int getCounter() {
        return counter;
    }

    public void run() {
        for (int f = i; f < a.length; f += k) {
            if (a[f] == 3) {
                counter++;
            }
        }
    }
}[/CODE]

[CODE lang="java" title="PrintThread"]public class PrintThread extends Thread{

    int counter;

    public void run() {
        //while Schleife? Währen die anderen Threads noch laufen
        if (counter % 100 == 0 ) {
            System.out.println(counter + "Vorkommen bisher gefunden!");
        }
        //Wenn die anderen Threads fertig sind
        System.out.println("Gesamtvorkommen: " + counter);
    }
}[/CODE]_


----------



## Jw456 (10. Feb 2022)

Final counter in der main Methode macht keinen Sinn.

Benutze eine public Instanzvariable dafür in der Klasse CountNumbers.

Natürlich musst du ein Objekt dieser Klasse erstellen. Und diese Instanz auch an die Threads übergeben. 

Oder eine Klassenvariable (static)

Tipp denke auch an synconisation der Threads wenn sie auf die gleiche Variable zugreifen.


----------



## Jw456 (10. Feb 2022)

> wie ich den Counter zwischen allen Threads "gleich" halte, sodass diese gegenseitig auf denselben Wert zugreifen und wie ich diesen dann an die PrintThread übergebe.


Wenn sich der counter während   der Thread läuft nicht ändert. Kannst du ihn ja dem Konstruktor übergeben. Und  in der Instanzvariablen vom Thread Speichen. 

Beim Thread Instanziren mit new musst du ihn dann mit übergeben.


----------



## gta008 (10. Feb 2022)

Vielen Dank für die Hilfe. Ich habe nun counter als public static int in der CountNumber Klasse gemacht, sodass nun die Klasse CountThread darauf zugreifen kann (mittels CountNumbers.counter). Nun habe ich das Problem, dass das Ergebnis nicht mit dem Korrekten Ergebnis übereinstimmt. Ich habe versucht dies mit einem synchronisierten Block zu versuchen, leider ohne Erfolg. Des Weiteren habe ich nicht genau verstanden wie ich das mit dem PrintThread einbringen soll.
[CODE lang="java" title="Count Numbers"]import java.util.*;

public class CountNumbers {

    public static int counter = 0;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("Geben Sie n ein: ");
        int n = sc.nextInt();
        System.out.print("Geben Sie k ein: ");
        int k = sc.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; ++i) {
            a_ = (int) (Math.random() * 10);
        }
        Object Lock = new Object();
        synchronized(Lock) {
            for (int i = 0; i < k; ++i) {
                Thread CountThread = new CountThread(k, i, n, a);
                CountThread.start();
            }
        }
        int correct = 0;
        for (int i = 0; i < a.length; ++i) {
            if (a == 3) {
                ++correct;
            }
        }
        System.out.println("Errechnte Lösung: " + counter);
        System.out.println("Korrekte Lösung: " + correct);
    }


}
[/CODE]_


----------



## Jw456 (11. Feb 2022)

Alle deine Threads können gleichzeitig auf die countervariablen zugreifen . Was nicht sein darf.
Also was liegt nahe diese Variable zu Synchronisieren. So das also immer nur ein Thread schreiben kann die andern dann warten müssen.


```
public class CountNumbers {

    public static synchronized int counter = 0;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("Geben Sie n ein: ");
        int n = sc.nextInt();
        System.out.print("Geben Sie k ein: ");
        int k = sc.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; ++i) {
            a[i] = (int) (Math.random() * 10);
        }
            for (int i = 0; i < k; ++i) {
                Thread CountThread = new CountThread(k, i, n, a);
                CountThread.start();
            }
```


----------



## Jw456 (11. Feb 2022)

Sollte das nicht klappen da  deine Variable static  ist benute eine  synchronized  Setter auf die Variable.
die Methode musst du dann im Thread aufrufen wenn eine "3" gefunden wurde.


```
public static synchronized void incrementCount() {
        counter++;
    }
```


----------



## gta008 (11. Feb 2022)

Vielen Dank für die Rückmeldung, ich habe es nun hinbekommen. Jetzt habe ich nur noch das Problem mit der PrintMethode, diese soll ja immer nach 100 weiteren Zählungen einen Outprint liefern.


----------



## gta008 (11. Feb 2022)

Folgendes Problem habe ich bei der Print-Methode: Es wird nicht bei jedem 100er Schritt ausgegeben, dass der Counter um 100 größer geworden ist. Der Print am Ende funktioniert. 

[CODE lang="java" title="CountNumbers"]//vorher wird noch finished auf false gesetzt
Thread print = new PrintThread();
        print.start();
        Thread[] threads = new Thread[k];
        for (int i = 0; i < k; ++i) {
            threads_ = new CountThread(i);
            threads.start();
        }
        for (int i = 0; i < k; ++i) {
            threads.join();
        }
        finished = true;[/CODE]

[CODE lang="java" title="PrintThread"]public class PrintThread extends Thread{

    public void run() {
        while(!CountNumbers.finished) {
            if (CountNumbers.getCounter() > 0 && CountNumbers.getCounter() % 100 == 0){
                System.out.println(CountNumbers.getCounter() + " Vorkommen bisher gefunden!");
            }
        }
        System.out.println("Gesamtvorkommen: " + CountNumbers.getCounter());
    }

}
[/CODE]_


----------



## Jw456 (11. Feb 2022)

Mit dem join warten auf Beendigung des Threads. Blockirst du tdem Main Thread mit dem Warten. Nicht so gut.

Ich würde in dem print Thread die anderen Threads starten da hast du auch die Instanz von denen und kannst  in deiner while Schleife testen ob alle beendet sind. Dann die end Ausgabe machen.
In der Scheife auch prüfen ob schon 100 gefunden wurden.


----------



## gta008 (11. Feb 2022)

Das bringt mich leider nicht wirklich weiter. Ich habe jetzt das ganze in die PrintThread Klasse geschrieben, aber ich weiß nicht wie ich prüfen kann, wann die 100 jeweils rum sind und jetzt auch durch das weglassen von join nicht, wann ich finished auf true setzen soll.
[CODE lang="java" title="PrintThread"]public class PrintThread extends Thread{

    boolean finished;

    public void run() {
        Thread[] threads = new Thread[CountNumbers.getK()];
        for (int i = 0; i < threads.length; ++i) {
            threads_ = new CountThread(i);
            threads.start();
        }
        int cache;
        while(!finished) {
            cache = CountNumbers.getCounter();
            if (cache > 0 && cache % 100 == 0){
                System.out.println(cache + " Vorkommen bisher gefunden!");
            }
        }
        System.out.println("Gesamtvorkommen: " + CountNumbers.getCounter());
    }

}
[/CODE]_


----------



## Jw456 (11. Feb 2022)

Dann schaue mal in die Doku  isAlive()





__





						Thread (Java Platform SE 7 )
					





					docs.oracle.com
				




Das mit dem finished in der while macht für mich auch wenig Sinn.
Eine Endlosschleife wenn alle Threads beendet sind  brichts du sie ab. Macht für mich mehr Sinn.
Oder eine Methode die das prüfen übernimmt.

Wie wäre es mit einem Konstruktor dem du das Array und die anderen Werte übergibst. Du brauchst sie  ja für deine Threads.



Das ist eine Hausaufgaben ich werde dir keinen Code geben.

Tipp prüfe in einer Schleife das alle Threads beendet sind. 
Dieses Ergebnis kannst du zum beenden der Endlos Schleife benutzen und somit auch zum beenden des Threads.


----------

