Threads Probleme mit synchronized

Nebelparder

Neues Mitglied
Hallo zusammen

So, nachdem ich mich nun mehrere Tage mit der Fehlersuche beschäftigt (und wirklich viel gelernt habe), bin ich am Ende meines Lateins. Ich finde den Fehler einfach nicht und bitte euch, mich zu unterstützen. ;(


Aufgabe:

Es geht darum, eine Bank mit 5 Konten zu erstellen, wobei jedes Konto zu Beginn 1000 EUR erhält.
Insgesamt sollen sodann 50 Threads erstellt, werden, die während rund 60 Sekunden nachfolgend beschriebenen Algorithmus ausführen sollen:

- wähle zwei zufällige Konten (A und B)
- ziehe von Konto A 100 EUR ab
- schreibe Konto B 100 EUR gut
- schlafe 2ms
- beginne von vorne, bis die 60 Sekunden rum sind


Mein Problem:

Das Programm kann wie gewünscht ausgeführt werden. Nur: die Werte, die am Ende ausgegeben werden, stimmen mal so gar nicht - die Summe aller Konten müsste ja nach wie vor 5000 betragen. Ich erhalte jedoch Werte jenseits von gut und böse - und weiss schlichtweg nicht weshalb. HELP!!! :shock:


Der Code

Java:
public class Processor {

	public static void main(String[] args) {

		Bank myBank = new Bank();
		Teller[] staff = new Teller[50];
		
		for(int i = 0; i < 50; i++)
		{
			String name = "Teller_" + i;
			staff[i] = new Teller(name,myBank);
			staff[i].start();
		}
		
		try {
			Thread.sleep(60000);
		}
		catch (InterruptedException e)
		{}
		
		for(int i = 0; i < 50; i++)
		{
			staff[i].interrupt();
		}
		
		myBank.zeigeBilanz();
	}
}

Java:
public class Teller extends Thread
{
	
	private Bank bank;
	
	public Teller(String name, Bank bank)
	{
		super(name);
		this.bank = bank;
	}
	
	public void run()
	{
		while( !isInterrupted() )
		{
			bank.bucheBelastung();
			bank.bucheGutschrift();
			
			try
			{
				Thread.sleep(2);
			}
			catch(InterruptedException e)
			{
				interrupt();
			}
		}
	}
}

Java:
public class Bank
{
	private Random random;
	private Konto[] konten;
	
	
	public Bank()
	{
		random = new Random();
		konten = new Konto[5];
		
		for(int i = 0; i < konten.length; i++) {
			konten[i] = new Konto(1000);
		}
	}
	
	
	public synchronized void bucheBelastung() {
		
		Konto a = konten[(random.nextInt(5))];
		a.setKontostand(a.getKontostand() - 100);
		
	}
	
	
	public synchronized void bucheGutschrift() {
		
		Konto b = konten[(random.nextInt(5))];
		b.setKontostand(b.getKontostand() + 100);
		
	}
		
	
	public void zeigeBilanz() {	
		
		for(int i = 0; i < konten.length; i++) {
			int saldo = konten[i].getKontostand();
			System.out.println("Konto " + i + ": " + saldo + " CHF");
		}
	}	
}



Vielen Dank für eure Unterstützung!!!

Gruss nebelparder
 

MasseElch

Aktives Mitglied
Sind es denn Werte über 5000 oder sind sie niedriger? (Ich nehme Mal an sie sind gewaltig hoch?)

Sind sie unter der Grenze könnte es daran liegen, dass meines WIssens nach interrupt() direkt da wo der Thread grad mit der Ausführung beschäftigt war unterbrochen wird. Demnach kann es passieren, dass der interupt() genau dann kommt, wenn nach der Belastung die Gutschrift kommen soll.

Dazwischen schmeißt er den Thread weg und schwupps wird das Geld zwar belastet aber nicht mehr gut geschrieben.

Java:
bank.bucheBelastung();
bank.bucheGutschrift();
 
Zuletzt bearbeitet:

Attila

Bekanntes Mitglied
Java:
public class Bank{
  //...
  public synchronized void bankOperation(){
    bucheBelastung();
    bucheGutschrift();
  }
  private void bucheBelastung(){...}
  private void bucheGutschrift(){...}
}

Java:
public class Teller extends Thread{
  //...
  while( !isInterrupted() ){
     bank.bankOperation();
     //...
}
 

Gucky

Top Contributor
Setzt interrupt nicht nur ein Flag und dann läuft der Thread noch bis zum Ende durch?
Hasz du mal debuggt? Dir nur einen Thread erstellt und dir die Operationen von diesem mal ausgeben lassen? Wenn es bei 50 Threads schief läuft, müsste es bei einem auch schief laufen. Lass dir den Code mal zeilenweise ausführen und guck dir die Belegungen der Variablen an und check, ob die passen.
 

Klösp

Aktives Mitglied
Ja, Interrupt ist nur ein boolean. Diese kann mit isInterrupted abgefragt werden.
In diesem Fall sollte das aber richtig sein, weil er bei in dem Fall aus der Schleife spring und die run-Methode vom Thread am Ende ist.

@Nebelparder
Ich hab das mal bei mir ausprobiert.
Konto hab ich einfach nur Getter/Setter+Konstruktor mit int Guthaben als Instanzvariable (ich denke so ist es bei dir auch).

Hast du dir auch mal die Summer ausgeben lassen. Die hat bei mir in den knapp 20 Versuchen bei mir immer gestimmt. Das die einzelnen Kontostände sehr "extrem" werden kann ja passieren, wenn halt zufällig ein Konto immer belastet wird und ein anderes sehr häufig Geld gutgeschrieben bekommt.

Allerdings sind 20 Test nicht wirklich eine Garantie, denn ich habe eigentlich auch vermutet, dass da ein Fehler drin ist.
Nämlich das, was Attila schon gezeigt hat.
Ich denke es gibt immer noch die Möglichkeit, dass zwei Threads gleichzeitig auf den Kontostand zugreifen. Nach einigen Durchläufen könnte es eventuell passieren, dass während Thread x gerade Guthaben gutschreiben möchte, Thread y gerade dabei ist Guthaben vom selben Konto abzuziehen.

Hat wie gesagt in meinen Test immer funktioniert, aber ich vermute, dass das trotzdem nicht ganz sicher ist. Ich lasse mich aber auch gerne belehren.
 

wef34fewrg

Aktives Mitglied
Hallo Nebelparder,

schreib grad von unterwegs und kann das nicht austesten, aber hier mal ein paar Gedanken zu deinem Fehler


1. zu deinen Unsummen:
Fall 1:
deine Methode setKontostand() sieht so aus
Java:
public void setKontostand(int saldo)
{
    //this.saldo ist der Kontostand
     this.saldo = saldo
}

Dann würde es wohl reichen in der Klasse Bank die Methode zeigeBilanz so zu ändern
Java:
public void zeigeBilanz() 
{ 
          //result ist neu
        int result = 0;
        for(int i = 0; i < konten.length; i++) 
        {
            int saldo = konten[i].getKontostand();
            result += saldo;
            System.out.println("Konto " + i + ": " + saldo + " CHF");
        }

Begründung:
Prinzipiell läuft dein Programm tatsächlich korrekt (auch wenn Attilas Lösung für logische Korrektheit relevant ist. Komm ich gleich zu)
Dein Problem ist, dass du nicht darauf achtest, ob Geld da ist oder nicht.
Konto 1 5000
Konto 2 0
Konto 3 0
Konto 4 -100 000
Konto 4 100 000

Summe = 5000
Die Summe ist also da, weil du beliebig positiv oder negativ wechselst.

Fall 2
deine Methode setKontostand() sieht so aus
Java:
public void setKontostand(int saldo)
{
    //this.saldo ist der Kontostand
     this.saldo += saldo
}

Geht gar nicht auf. Da du allerdings schon in deiner Bankklasse die nötige Addition bzw. Subtraktion durchführst ist das wohl nicht deine Lösung.

2. Atilas Lösung

Finde ich besser als deine zwei synchronized Methoden. In deinem Fall wäre sie unnötig, da deine Buchungen nicht verloren gehen. Schlecht programmiert ist es natürlich dennoch und um keine verlorenen Buchungen zu erhalten (bei Richtigkeit der Lösung) wirst du um Atilas Lösung (bzw. einer Semaphorelösung bzw. eines gemeinsamen Lockobjektes) nicht herum kommen.
Eine Buchung sollte nur möglich sein, wenn das Saldo des Kontos nicht negativ wird. Habt ihr denn schon wait und notifyAll() besprochen?

3. weitere Probleme

Du solltest versuchen, falls deine Programmierkenntnisse es zu dem Zeitpunkt zu lassen, nicht die ganze Bank zu sperren, sondern nur die beiden benötigten Konten. Die ganze Bank zu sperren bedeutet, dass alle anderen Threads warten müssen und die Parallelität unnötig eingeschränkt wird. Wenn Thread a Konto 1 und 2 in Arbeit hat, wieso soll Thread b darauf warten müssen Konto 3 und 4 zu beackern?

In der Klasse Processor solltest du nach der interrupt Aufforderung unbedingt in einer zweiten for Schleife (oder in der selben) mit staff.join() arbeiten. Hintergrund ist der, dass der Main-Thread womöglich die Bilanz schon aufruft, bevor alle Threads ihre Arbeit getan haben. Interrupt ist nur eine Aufforderung an den Thread, aber kein Zwang der instant umgesetzt wird.

In Teller ist in der run Methode der zweite Aufruf von interrupt() eigentlich nicht notwendig, wenn du den Try Block um die while Schleife baust. Aber auch nicht schlimm.


@MasseElch

Was du beschreibst ist die stop() Methode, die ja als deprecated gekennzeichnet wurde, damit genau dieser Fall nicht passiert.


So, jetzt hoffe ich, ich hab mich nicht total blamiert, weil ich mir das alles von Hand zusammengereimt habe. :D

Grüße


Allerdings sind 20 Test nicht wirklich eine Garantie, denn ich habe eigentlich auch vermutet, dass da ein Fehler drin ist.
Nämlich das, was Attila schon gezeigt hat.
Ich denke es gibt immer noch die Möglichkeit, dass zwei Threads gleichzeitig auf den Kontostand zugreifen. Nach einigen Durchläufen könnte es eventuell passieren, dass während Thread x gerade Guthaben gutschreiben möchte, Thread y gerade dabei ist Guthaben vom selben Konto abzuziehen.

Hat wie gesagt in meinen Test immer funktioniert, aber ich vermute, dass das trotzdem nicht ganz sicher ist. Ich lasse mich aber auch gerne belehren.

Naja das Bankobjekt ist ja gesperrt. Das heisst in der Zeit in der ein Thread abhebt, kann ein anderer nicht gleichzeitig auf das selbe Konto was draufzahlen.

Atilas Methode ist natürlich richtig, da auch Konsistenz zwischen den beiden Methoden notwendig ist, aber auf die wird hier ja nicht geachtet, weswegen, wie du schon sagst, diese Unsummen aufkommen
 
Zuletzt bearbeitet:

Klösp

Aktives Mitglied
@Rock45

Jop richtig. Das synchronized bewirkt, dass sich nicht nicht zwei Threads gleichzeitig in irgendeinem synchronisierten Abschnitt eines Objekts befinden dürfen und nicht, dass sich nicht mehrere Threads im selben synchronsierten Abschnitt einer Klasse befinden duerfen. (außer Klassenmethoden).

Sorry, war ein Denkfehler (schon etwas spät)
Also was ich dies bezüglich eben geschrieben habe bitte nicht beachten:oops:
 

Nebelparder

Neues Mitglied
Hallo zusammen

Wow, was für ein Feedback. Leute, ihr seid einfach genial. Vielen herzlichen Dank!! :applaus:

Dank euren Anregungen, hab ich denn auch tatsächlich den Fehler gefunden.
Interessanterweise lag dieser direkt dort, wo ich dachte, zumindest die Klasse müsse korrekt sein.
In der Klasse Account.

Ich hatte bislang einen Getter und einen Setter verwendet, um den Kontostand abzufragen und neu zu setzen.
Die Addition/Subtraktion fand in der Klasse Bank statt.

Nun hab ich das so geändert, dass die Klasse Bank lediglich das Bankkonto aufruft und den Betrag weitergibt.
In der Klasse Account findet sich nur noch eine synchronized-Methode um den erhaltenen Betrag zum Kontostand hinzuzuzählen, resp. abzuziehen. Die Methoden der Klasse Bank sind indessen normal (sprich nicht synchronized).

Und es funktioniert. Kein Wunder: entspricht ja auch der Lösung unseres Schulbuchs (verstreut über ca. 100 Seiten, was man erst noch verstehen muss :oops: )


Nochmals herzlichen Dank - und bis zur nächsten Frage - das Studium hat gerade erst begonnen :lol:

Gruss nebelparder
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
D Rekursions Probleme / frage Java Basics - Anfänger-Themen 4
P JDK installieren Probleme bei der Java-Installation Java Basics - Anfänger-Themen 8
C Probleme mit Byte konvertieren nach int Java Basics - Anfänger-Themen 10
P Probleme mit NetBeans: Wie lässt sich jar. Datei an einem MacBook öffnen Java Basics - Anfänger-Themen 21
I Projekte in IDE untereinander sharen / Probleme beim Build Java Basics - Anfänger-Themen 8
MiMa Probleme mit Datentyp long ?? Java Basics - Anfänger-Themen 2
T Probleme beim Import eines Git-Repos Java Basics - Anfänger-Themen 2
Jxhnny.lpz TicTacToe Spiel vs Computer. (Probleme) Java Basics - Anfänger-Themen 7
B Quiz mit RMI Probleme mit RMI start Java Basics - Anfänger-Themen 4
httprt Probleme bei dem erstellen von leveln in meinem Spiel Java Basics - Anfänger-Themen 2
berserkerdq2 Habe eine Klasse, welche public ist, diese hat eine public Methode, die nicht static ist. Wenn ich nun versuche aufzurufen Probleme? Java Basics - Anfänger-Themen 8
V Probleme Guessing Game Java Basics - Anfänger-Themen 8
hebein PDF Ausdruck auf Drucker - Probleme mit Format Java Basics - Anfänger-Themen 17
R JMenu/JMenuItem Probleme Java Basics - Anfänger-Themen 2
B Static vs non static und Probleme daraus Java Basics - Anfänger-Themen 13
J Probleme mit dem Debugger Java Basics - Anfänger-Themen 4
I Probleme mit OutputStream - Datei lässt sich nicht öffnen Java Basics - Anfänger-Themen 4
J Probleme mit Kompilierung Java Basics - Anfänger-Themen 11
B Probleme mit Zugriff auf Dateisystem Windows 10 ( jFileChooser) Java Basics - Anfänger-Themen 17
W Objekte über Scanner Input; ToString Probleme... Java Basics - Anfänger-Themen 4
C Probleme mit paintComponent Java Basics - Anfänger-Themen 13
P Probleme mit JUnit-Tests, es kommt was anderes raus als bei manuellen Tests Java Basics - Anfänger-Themen 5
E JavaFX Editor Probleme mit der Zwischenablage Java Basics - Anfänger-Themen 12
C Probleme mit dem Erstellen und Importieren von Packages Java Basics - Anfänger-Themen 6
3 OOP erste Versuche, OOP zu verstehen. Probleme mit gettern und settern Java Basics - Anfänger-Themen 4
R Erste Schritte Probleme bei 2D Spielfeld, mit einzufügender "Person" Java Basics - Anfänger-Themen 5
P Probleme bei der Installation von JavaFX Java Basics - Anfänger-Themen 3
S Mehrere Probleme im Code Java Basics - Anfänger-Themen 7
D Probleme mit JFrame und der Größe Java Basics - Anfänger-Themen 8
Dimax String Probleme Java Basics - Anfänger-Themen 12
N Probleme beim printen von Arrays durch for Schleife Java Basics - Anfänger-Themen 3
Splayfer Java Array Probleme Java Basics - Anfänger-Themen 3
J Probleme bei IllegalArgumentException "werfen". Java Basics - Anfänger-Themen 1
K Probleme bei der Ausgabe - komme nicht weiter :/ Java Basics - Anfänger-Themen 15
X Probleme im Umgang mit PriorityQueue Java Basics - Anfänger-Themen 75
D Probleme mit dem Windowbuilder und JComboBox Java Basics - Anfänger-Themen 2
M Regex Probleme (mal wieder) Java Basics - Anfänger-Themen 3
tom.j85 TicTacToe - probleme beim Casten Java Basics - Anfänger-Themen 6
J Probleme mit Vererbung Java Basics - Anfänger-Themen 4
X Probleme mit Übungsaufgaben zu Zahlentypen Java Basics - Anfänger-Themen 4
G Probleme bei Aufgabe Java Basics - Anfänger-Themen 12
P Erste Schritte Probleme mit dem Programmieren Java Basics - Anfänger-Themen 12
B Probleme bei einer Aufgabe Java Basics - Anfänger-Themen 19
Franzi1001 Probleme mit Eclipse Java Basics - Anfänger-Themen 7
T Probleme bei Installation von JDK Java Basics - Anfänger-Themen 2
C Probleme mit String-Vergleich Java Basics - Anfänger-Themen 4
C Probleme bei Regex Java Basics - Anfänger-Themen 9
V Probleme mit Arrays Java Basics - Anfänger-Themen 8
D Kleine Probleme mit Split-Befehlen Java Basics - Anfänger-Themen 5
T Probleme mit Strings Java Basics - Anfänger-Themen 6
G Probleme bei Frame aufgaben Java Basics - Anfänger-Themen 6
N Probleme mit dem ActionListener Java Basics - Anfänger-Themen 4
D Probleme beim Kompelieren mache ich etwas falsch ? Java Basics - Anfänger-Themen 3
L Probleme mit Java Java Basics - Anfänger-Themen 3
S Probleme mit abspielen einer .wav Datei Java Basics - Anfänger-Themen 2
J Probleme bei der Umwandlung einer Farbe von Hex zu RGB Java Basics - Anfänger-Themen 8
K Probleme beim Programm schreiben - Lesen von Dateiinhalten -zaehlen von Wörtern/ Buchstaben Java Basics - Anfänger-Themen 4
M Probleme beim aktualisieren eines JPanels Java Basics - Anfänger-Themen 7
J Probleme beim Array ausgeben Java Basics - Anfänger-Themen 4
M Probleme bei rekursiver Zuordnung Java Basics - Anfänger-Themen 1
I Probleme mit 2 dimensionale Arrays Java Basics - Anfänger-Themen 3
H Best Practice View probleme Java Basics - Anfänger-Themen 2
B Probleme mit Kreisberechnung Java Basics - Anfänger-Themen 15
E Probleme mit Scanner Java Basics - Anfänger-Themen 4
J Eclipse Export Probleme Java Basics - Anfänger-Themen 25
M Probleme beim verwenden von Packages Java Basics - Anfänger-Themen 6
D Probleme mit der Übergabe einer BorderPane Java Basics - Anfänger-Themen 2
J Interface Probleme bei der Implementierung Java Basics - Anfänger-Themen 1
BlueFox Tabelle in der Konsole ausgeben - Probleme Java Basics - Anfänger-Themen 1
G Methoden Probleme beim Methodenaufruf Java Basics - Anfänger-Themen 2
V Klassen ObjectInputStream ->ReadObject Probleme Java Basics - Anfänger-Themen 5
P Probleme mit der Do-Schleife Java Basics - Anfänger-Themen 2
F Erste Schritte Compiling Probleme Java Basics - Anfänger-Themen 13
S Neuling und Probleme bei Schulaufgabe Java Basics - Anfänger-Themen 5
J Anfänger: ActionListener und ProcessBuilder machen Probleme Java Basics - Anfänger-Themen 6
S Erste Schritte 2D Grafik Probleme mit KeyListener. Java Basics - Anfänger-Themen 18
M Array mit eigenem Datentyp probleme beim übergeben Java Basics - Anfänger-Themen 6
M Probleme mit Eclipse Java Basics - Anfänger-Themen 20
G Probleme beim casten von double zu int Java Basics - Anfänger-Themen 3
E 2 Probleme - Datum & private finale Variablen Java Basics - Anfänger-Themen 5
S Compiler-Fehler javac hat Probleme mit Paketen unter OSX Java Basics - Anfänger-Themen 2
J Probleme beim schreiben von Dateien Java Basics - Anfänger-Themen 5
B Variablen Probleme mit Eclipse Java Basics - Anfänger-Themen 6
H Mouse- und KeyListener Probleme? Java Basics - Anfänger-Themen 5
A Probleme beim zykl. aktulisieren von Daten in JTable Java Basics - Anfänger-Themen 3
I Probleme bei Verzeichnissanalyse Java Basics - Anfänger-Themen 12
F Probleme mit privaten Klassen (abstrakten Klassen) Java Basics - Anfänger-Themen 1
H Probleme mit Klassen...oder: Eine Uhr Java Basics - Anfänger-Themen 9
G Probleme mit Konsole Java Basics - Anfänger-Themen 4
S Probleme mit GamGrid Spiel-Erstellung => Actor reagiert nicht auf Tastatur Java Basics - Anfänger-Themen 2
G Probleme mit Eclipse oder der URL Klasse Java Basics - Anfänger-Themen 5
W Verständnis Probleme bei der while-Schleife und continue Java Basics - Anfänger-Themen 21
M Probleme mit Anzeigen von String in GUI und if-Anweisung Java Basics - Anfänger-Themen 9
T Konstruktor Probleme Java Basics - Anfänger-Themen 3
W Methoden Probleme mit der Scanner Methode Java Basics - Anfänger-Themen 2
F Ja Nein Abfrage und andere Probleme Java Basics - Anfänger-Themen 5
L If Anweisung mit ArrayList Probleme Java Basics - Anfänger-Themen 6
littles_de Simbad Simulator probleme mit Sensordaten... Java Basics - Anfänger-Themen 0
M Erste Schritte Probleme beim Verknüpfen von Methoden Java Basics - Anfänger-Themen 15
A Probleme beim Methodenaufruf von Object[] ! Java Basics - Anfänger-Themen 12

Ähnliche Java Themen

Neue Themen


Oben