ich bin am rumprobieren mit synchronisation gewesen und dabei auf folgendes Problem gestosen:
Java:
publicclassSpeicherproblem{int counter =0;publicstaticvoidmain(String[] args){Speicherproblem s =newSpeicherproblem();
s.test();}publicvoidtest(){newThread(newInkrementor()).start();newInkrementor().run();System.out.println(counter);}publicsynchronizedvoidadd(){
counter++;}publicclassInkrementorimplementsRunnable{@Overridepublicvoidrun(){for(int i =1; i <=10000; i++){add();}}}}
Ich erstelle hierbei zwei Inkrementoren, die in verschiedenen Threads counter um eins erhöhen.
Auch wenn sie dies in einer synchronized Methode machen, kommt als result ein zufälliger Wert zwischen
10.000 und 20.000 herraus.
Warum, wie macht mans richtig?
hm, hab jetzt hier am lappi kein eclipse zum testen, aber rein vom gefühl her sieht das n bischen merkwürdig aus. hast du dich vorher mal eigehend mit dem thema concurrency / threads beschäftigt? was soll denn überhaupt rauskommen? 20.000?
also was so auffällt beim drüberschauen:
1. zeile 3 - vielleicht volatile setzen
2. zeilen 12 & 13 - warum die verschiedenen aufrufe? und niemals run() aufrufen, nur start(), sonst ist es eine simple methode, kein multithreading
3. die nested class nicht public machen, sonst braucht sie ne eigene datei. kompiliert dass denn so eigentlich? *grübel*
würd grundsätzlich nochmal über den code nachdenken
Dein Problem entsteht durch diese Methode. Wenn die Zeile mit dem println ausgeführt wird, dann ist der eine Inkrementor fertig, d.h. counter ist mindestens 10000. Der Fortschritt des parallelen Threads ist aber völlig unklar, er kann zwischen 0 (kam noch nicht zum Zug) und 10000 (ist bereits fertig) liegen.
Funktionieren müsste es so (habs nicht getestet)
Java:
publicvoidtest(){Thread t =newThread(newInkrementor());
t.start();newInkrementor().run();
t.join();System.out.println(counter);}
Ich habe jetzt counter volatile gemacht, bringt nichts.
Zu run() vs start().
Schaut nochmal hin, das run() bezieht sich lediglich auf die Klasse Inkrementor, welche von Runnable abgeleitet ist.
Funktionieren tut das so:
Ich starte einen neuen Thread der dann anfängt counter zu erhöhen.
Derweil erhöhe ich im Ursprungsthread counter ebenfalls (new Inkrementor.run()).
Die nested class ist schlecht mit public, sehe ich ein, habe das auch sofort private gemacht.
Auswirkungen auf das Ergebnis hatte dies aber natürlich nicht.