Frage zu Datenzugriff bei new Thread(new Runnable)

Antragon

Mitglied
Hallo erstmal,
ich habe da mal eine Frage: Zunächst aber erstmal einige Hintergrundinformationen zu meinem "Problem".

Ich habe eine Klasse CMultThread die das Interface Runnable implementiert. In dieser Klasse wird in der Methode run() eine Berechnung durchgeführt deren Ergebnis in einer privaten Klassenvariable gespeichert wird. Auf den Wert dieser Variable kann man dann mittels einer Methode getValue() zugreifen.

Innerhalb einer anderen Klasse CMain wird dann ein 2-Dimensionales Thread-Array angelegt, in dessen einzelne Felder dann wiederum Objekte vom Typ Thread gespeichert werden, denen als Übergabeparameter ein Objekt der Klasse CMultThread übergeben wurde:
Java:
matrixC[z][s] = new Thread(new CMultThread(...));

Nun meine Frage:
Wie kann ich nach Abschluss der Berechnungen mittels getValue() auf die in CMultThread errechneten Ergebnisse zugreifen?

Ein Aufruf der Form "matrixC[z]." zeigt mir halt nur die Methoden der Klasse Thread, da die Elemente in dem Array ja einzelne Threads sind.

Anbei noch mal ein kleines UML-Bild, das - so hoffe ich - das ganze verständlicher macht.

Grüße, Antragon
 

Anhänge

  • Threads-UML.jpg
    Threads-UML.jpg
    53,2 KB · Aufrufe: 40
Und wieso erweitert deine Klasse(die ja schon den Namen Thread trägt) nicht einfach Thread und überschreibt dort die run? Dann kannst du auch später die Methode getValue() aufrufen, bzw halt ganz normal auf CMultThread casten...

Ansonsten müsstest du denke ich nicht die Threads im Array ablegen, sondern ein Runnable-Array anlegen und eben dort deine CMultThread-Instanzen ablegen.
 
Dabei handelt es sich um eine Hausaufgabe - d.h. die Idee eine Klasse mit Runnable Interface als Objekt an einen Thread zu übergeben und diesen in einem Thread-Array zu speichern ist also nicht auf meinem Mist gewachsen :bahnhof:
 
mein vorschlag wäre, bau der CMain klasse ne methode die von außen den wert rein geben kann.
dann machste die methode synchronised un zur sicherheit das array wo die sachn rein kommen auch noch... dann noch fix deine CMultThread so ändern das die CMain in den constructor soll un dann in der run() die methode der CMain aufrufen un den wert rein schieben
 
mein vorschlag wäre, bau der CMain klasse ne methode die von außen den wert rein geben kann.
dann machste die methode synchronised un zur sicherheit das array wo die sachn rein kommen auch noch... dann noch fix deine CMultThread so ändern das die CMain in den constructor soll un dann in der run() die methode der CMain aufrufen un den wert rein schieben
Irgendwie komm ich nicht so ganz dahinter, was du meinst :autsch:
Aber um das Problem genauer zu Beschreiben, hier mal die Aufgabenstellung:

Schreiben Sie eine Klasse ’multThread.java’, die das Interface Runnable implementiert. In der run()
Methode realisieren Sie dann die Berechnung eines Elementes der Produktmatrix. Da diese Berechnung
sowohl von der Position des Elementes, als auch von den entsprechenden Werten der Matrizen
A und B abhängt, übergeben Sie diese Parameter an den Konstruktor der multThread Klasse.

In dem Hauptprogram erzeugen Sie nun ein zweidimensionales Array von n×n Thread Objekten.
An den Konstruktor des jeweiligen Threads übergeben Sie das zuvor erzeugte multThread Objekt
mit den entsprechenden Parametern. Rufen Sie dann die Methode start() auf.

Stellen Sie sicher, dass alle Threads ihre Arbeit beendet haben, bevor Sie die Werte der Ergebnismatrix
C ausgeben. Dies kann mittels der Methode join() realisiert werden.


Meine beiden Klassen sehen im Moment wie folgt aus:
Java:
import java.util.Random;

public class CMain
{
/* 
 * Variablendeklarationsblock
 */	
	private static final int intervall = 100;
	private int dim = 3; // Dimension der Matrizen
	private Random randomizer = new Random(); // Zufallszahl

/*	private double[][] matrixA = new double[dim][dim];
	private double[][] matrixB = new double[dim][dim];
	
*/
	private Thread[][] matrixC = new Thread[dim][dim];
	
	// Vorbelegte Matrizen zur Fehlerkontrolle
	private double[][] matrixA = {{1,2,3},{4,5,6},{7,8,9}};
	private double[][] matrixB = {{9,8,7},{4,5,6},{3,2,1}};
	
/*
 * Methodendeklarationsblock
 */
		
	/**
	 * Konstruktor der Applikation
	 */
	public CMain()
	{
		//createMatrices();
		for(int z=0; z < dim; z++)
		{
			for(int s=0; s < dim; s++)
			{
				int[] valuePos = {z,s};
				//Lösungsmatrix mit Berechnungsthreads füllen
				matrixC[valuePos[0]][valuePos[1]] = new Thread(new CMultThread(valuePos, getZeilenVektor(valuePos), getSpaltenVektor(valuePos)));
				// Thread in Lösungsmatrix starten
				matrixC[valuePos[0]][valuePos[1]].start();
				try
				{
					matrixC[valuePos[0]][valuePos[1]].join();
				} catch (InterruptedException e)
				{
					System.out.println(e.getMessage());
				}
			}
		}
		matrixToString();
	}
	
	/**
	 * Erzeugt die mit Zufallswerten gefüllten Matrizen A und B. Der Wertebereich liegt in dem offenen
	 * Intervall (-intervall, intervall).
	 */
	private void createMatrices()
	{
		for(int z=0; z < dim; z++)
			for(int s=0; s < dim; s++)
			{
				if (Math.random() < 0.5)
					matrixA[z][s] = (-1) * randomizer.nextDouble() * intervall;
				else
					matrixA[z][s] = randomizer.nextDouble() * intervall;
				if (Math.random() < 0.5)
					matrixB[z][s] = (-1) * randomizer.nextDouble() * intervall;
				else
					matrixB[z][s] = randomizer.nextDouble() * intervall;
			}
	}
	
	/**
	 * Erstellt den benötigten Zeilenvektor für die zu errechnende
	 * Stelle
	 * @param pos vom Typ int[2] erwartet die Matrix-Koordinaten, für die
	 * zu berechnende Stelle
	 */
	private double[] getZeilenVektor(int[] pos)
	{
		double[] zV = new double[dim];
		for(int s=0; s < dim; s++)
		{
			zV[s] = matrixA[pos[0]][s];
		}
		return zV;
	}

	/**
	 * Erstellt die benötigten Spaltenvektoren für die zu errechnende
	 * Stelle
	 * @param pos vom Typ int[] erwartet die Matrix-Koordinaten, für die
	 * zu berechnende Stelle
	 */
	private double[] getSpaltenVektor(int[] pos)
	{
		double[] sV = new double[dim];
		for(int s=0; s < dim; s++)
		{
			sV[s] = matrixB[s][pos[1]];
		}
		return sV;
	}	
	
	/**
	 * Gibt die Ergebnismatrix aus.
	 */
	private void matrixToString()
	{
		for(int z=0; z < dim; z++)
			for(int s=0; s < dim; s++)
				System.out.println(matrixC[z][s].currentThread());
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args)
	{
		CMain main = new CMain();
	}
}
Java:
public class CMultThread implements Runnable
{
/* 
 * Variablendeklarationsblock
 */	
	private double valueC = 0.0d;
	private int[] position;
	private double[] zeilenVektor_A;
	private double[] spaltenVektor_B;
	
/*
 * Methodendeklarationsblock
 */
	/**
	 * Konstruktor der zwei Parameter erwartet
	 * @param position vom Typ int[] erwartet die Position der berechneten Stelle
	 * @param zeilenVektor_A vom Typ double[]
	 * @param spaltenVektor_B vom Typ double[]
	 */
	public CMultThread(int[] position, double[] zeilenVektor_A, double[] spaltenVektor_B)
	{
		this.position = position;
		this.zeilenVektor_A = zeilenVektor_A;
		this.spaltenVektor_B = spaltenVektor_B;
	}
	
	/**
	 * Liefert die Position des errechneten Matrizen-Elements zurück.
	 * @return position vom Typ int[]
	 */
	public int[] getPosition()
	{
		return position;
	}
	
	/**
	 * Liefert das errechnete Matrizen-Element zurück.
	 * @return valueC vom Typ double
	 */
	public double getValue()
	{
		return valueC;
	}
	
	/**
	 * Berechnet aus den Eingabevektoren das Matrizen-Element
	 */
	public void run()
	{
		int dim = zeilenVektor_A.length;
		for(int i=0; i < dim; i++)
		{
			valueC += zeilenVektor_A[i]*spaltenVektor_B[i];
		}
		//System.out.println(toString());
	}
	
	public String toString()
	{
		String ausgabe = "Matrix C ["+position[0]+"]["+position[1]+"] = "+getValue();
		return ausgabe;
	}
}
Die Berechnung der Matrizenelemente funktioniert korrekt, das Problem ist halt, dass ich von CMain aus nicht auf die valueC-Werte von CMultThread zugreifen kann, d.h. ich kann nach Beendigung der aller Threads nicht auf die Einzelergebnisse zugreifen um somit die Ergebnismatrix C darzustellen.

Grüße, Antragon
 
Du packst in deine Matrix die Threads.
Pack da doch die Klassen rein, dir das Runnable implementieren und starte die Matrix-Inhalte.

statt:
Java:
               matrixC[valuePos[0]][valuePos[1]] = new Thread(new CMultThread(valuePos, getZeilenVektor(valuePos), getSpaltenVektor(valuePos)));
                // Thread in Lösungsmatrix starten
                matrixC[valuePos[0]][valuePos[1]].start();

vielleicht:

Java:
               matrixC[valuePos[0]][valuePos[1]] = new CMultThread(valuePos, getZeilenVektor(valuePos), getSpaltenVektor(valuePos));
                // Thread in Lösungsmatrix starten
                new Thread(matrixC[valuePos[0]][valuePos[1]]).start();

(ungetestet)
 
Zunächst einmal danke für eure Hilfsversuche!

@Onkel Hatti
Dein Lösungsansatz führt zu einem Type mismatch, bei matrixC handelt es sich ja um ein Array von Threads, also:
Java:
private Thread[][] matrixC = new Thread[dim][dim]
Ferner ginge die Lösung an der Aufgabenstellung vorbei...

Es muss doch eine Möglichkeit geben, an die "Daten" der Objekte von CMultThread heranzukommen, immerhin werden ja Objekte dieser Klasse instanziert.

Grüße, Antragon
 
Ja, klar kommt da ne Exception. CMultThread ist halt nicht Thread.
Also muss die Matrix lauten:
statt:

Java:
private Thread[][] matrixC = new Thread[dim][dim];

Java:
private CMultThread[][] matrixC = new CMultThread[dim][dim];

Dann sollte meine Lösung klappen.
Aber das geht ja an der Aufgabenstellung vorbei, es soll ja eine Thread-Matrix erstellt werden.
Na schön, Hatti Lösungsansatz:

Es soll ja eh auf alle Threads gewartet werden, kein synchronisieren. join() ist also soweit OK.
ich tät mir eine ArrayList<CMultThread> deklarieren, CMultThread initialisieren, in die ArrayList und mit new Thread(meinCMultThread) in die Matrix so wie dus bereits gemacht hast.
Nachdem alle Threads fertig sind, über die ArrayList iterieren, und alle CMultThreads nach dem Ergebnis fragen.
Vorteil:
Alle CMultThreads sind in der ArrayList in der Reihenfolge, wie sie erstellt wurden.
Das Ergebnis wird also in der richtigen Reihenfolge sein.

Lösungsansatz Hatti2:

dem Konstruktor der CMultThread wird noch CMain übergeben.
In CMain wird eine Methode erstellt, die die Werte aud dem Thread als Parameter hat.
Der Thread ruft nach abarbeiten der Berechnung diese Methode der CMain mit dem Ergebnis als Parameter auf.
Nachteil:
Welcher Thread zuerst fertig ist, kann man nicht wissen.

Hatti

Edit:

Zitat:

Es muss doch eine Möglichkeit geben, an die "Daten" der Objekte von CMultThread heranzukommen, immerhin werden ja Objekte dieser Klasse instanziert.

Zitat ende.

Ja, klar, theoretisch schon, aber du hast nichts mehr, womit du auf die Objekte zugreifen kannst.
Du rufst nur
new CMultThread(...)
auf. Da geht die Referenz verloren. Ruf
CMultThread cmt=new CMultThread(...) auf und über cmt hast du den Zugriff aufs Objekt.
 
Zuletzt bearbeitet:
Ich danke dir für die Hilfestellung!
Ich werde wohl die Lösung mit der ArrayList umsetzen - schade, dass man nicht auch über Thread auf die Runnable-Instanzen zugreifen kann.

Grüße, Antragon

EDIT: Für jeden, der irgendwann einmal ein ähnliches Problem haben sollte oder den es interessiert, hier mal meine Lösung der Aufgabenstellung:

Java:
import java.util.*;

public class CMain
{
/* 
 * Variablendeklarationsblock
 */	
	private static final int intervall = 100;
	private int dim = 3; // Dimension der Matrizen
	private Random randomizer = new Random(); // Zufallszahl

	private CMultThread[][] multThreadList = new CMultThread[dim][dim];
	
	private double[][] matrixA = new double[dim][dim];
	private double[][] matrixB = new double[dim][dim];
	
	private Thread[][] matrixC = new Thread[dim][dim];
	
	// Vorbelegte Matrizen zur Fehlerkontrolle
/*	private double[][] matrixA = {{1,2,3},{4,5,6},{7,8,9}};
	private double[][] matrixB = {{9,8,7},{4,5,6},{3,2,1}};
	*/
	
/*
 * Methodendeklarationsblock
 */
		
	/**
	 * Konstruktor der Applikation
	 */
	public CMain()
	{
		createMatrices();
		for(int z=0; z < dim; z++)
		{
			for(int s=0; s < dim; s++)
			{
				// Positionen innerhalb der Matrizen
				int[] valuePos = {z,s};
				//Lösungsmatrix mit Berechnungsthreads füllen
				CMultThread runnableElement = new CMultThread(valuePos, getZeilenVektor(valuePos), getSpaltenVektor(valuePos));
				multThreadList[z][s] = runnableElement;
				Thread matrixElementThread = new Thread(runnableElement);
				matrixC[valuePos[0]][valuePos[1]] = matrixElementThread;
				// Berechnungsthread in Lösungsmatrix starten
				matrixC[valuePos[0]][valuePos[1]].start();
				try
				{
					// Auf Beendigung des jeweils gestarteten Thread warten
					matrixC[valuePos[0]][valuePos[1]].join();
				} catch (InterruptedException e)
				{
					System.out.println(e.getMessage());
				}
			}
		}
		matrixToString();
	}
	
	/**
	 * Erzeugt die mit Zufallswerten gefüllten Matrizen A und B. Der Wertebereich liegt in dem offenen
	 * Intervall (-intervall, intervall).
	 */
	private void createMatrices()
	{
		for(int z=0; z < dim; z++)
			for(int s=0; s < dim; s++)
			{
				if (Math.random() < 0.5)
					matrixA[z][s] = (-1) * randomizer.nextDouble() * intervall;
				else
					matrixA[z][s] = randomizer.nextDouble() * intervall;
				if (Math.random() < 0.5)
					matrixB[z][s] = (-1) * randomizer.nextDouble() * intervall;
				else
					matrixB[z][s] = randomizer.nextDouble() * intervall;
			}
	}
	
	/**
	 * Erstellt den benötigten Zeilenvektor für die zu errechnende
	 * Stelle
	 * @param pos vom Typ int[2] erwartet die Matrix-Koordinaten, für die
	 * zu berechnende Stelle
	 */
	private double[] getZeilenVektor(int[] pos)
	{
		double[] zV = new double[dim];
		for(int s=0; s < dim; s++)
		{
			zV[s] = matrixA[pos[0]][s];
		}
		return zV;
	}

	/**
	 * Erstellt die benötigten Spaltenvektoren für die zu errechnende
	 * Stelle
	 * @param pos vom Typ int[] erwartet die Matrix-Koordinaten, für die
	 * zu berechnende Stelle
	 */
	private double[] getSpaltenVektor(int[] pos)
	{
		double[] sV = new double[dim];
		for(int s=0; s < dim; s++)
		{
			sV[s] = matrixB[s][pos[1]];
		}
		return sV;
	}	
	
	/**
	 * Gibt die Ergebnismatrix aus.
	 */
	private void matrixToString()
	{
		for(int z=0; z < dim; z++)
		{
			for(int s=0; s < dim; s++)
			{
				System.out.print(multThreadList[z][s].toString()+"\t");
			}
			System.out.println();
		}
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args)
	{
		CMain main = new CMain();
	}
}
Java:
public class CMultThread implements Runnable
{
/* 
 * Variablendeklarationsblock
 */	
	private double valueC = 0.0d;
	private int[] position;
	private double[] zeilenVektor_A;
	private double[] spaltenVektor_B;
	
/*
 * Methodendeklarationsblock
 */
	/**
	 * Konstruktor der zwei Parameter erwartet
	 * @param position vom Typ int[] erwartet die Position der berechneten Stelle
	 * @param zeilenVektor_A vom Typ double[]
	 * @param spaltenVektor_B vom Typ double[]
	 */
	public CMultThread(int[] position, double[] zeilenVektor_A, double[] spaltenVektor_B)
	{
		this.position = position;
		this.zeilenVektor_A = zeilenVektor_A;
		this.spaltenVektor_B = spaltenVektor_B;
	}
	
	/**
	 * Liefert die Position des errechneten Matrizen-Elements zurück.
	 * @return position vom Typ int[]
	 */
	public int[] getPosition()
	{
		return position;
	}
	
	/**
	 * Liefert das errechnete Matrizen-Element zurück.
	 * @return valueC vom Typ double
	 */
	public double getValue()
	{
		return valueC;
	}
	
	/**
	 * Berechnet aus den Eingabevektoren das Matrizen-Element
	 */
	public void run()
	{
		int dim = zeilenVektor_A.length;
		for(int i=0; i < dim; i++)
		{
			valueC += zeilenVektor_A[i]*spaltenVektor_B[i];
		}
		//System.out.println(toString());
	}
	
	public String toString()
	{
		double roundedValue = Math.round(valueC * 100.) / 100.;
		String ausgabe = "Matrix C ["+position[0]+"]["+position[1]+"] = "+roundedValue;
		return ausgabe;
	}
}
 
Zuletzt bearbeitet:

Zurück
Oben