eine Folge dieses ganzen Memory-Ignorierens ist, dass z.B. in GUI-Programmen mit eigenen Thread vs. EDT für paint + Listener der Zugriff auf alle gemeinsamen Variablen synchronisiert werden muss,
ist es richtig, dass theoretisch der EDT das intern oft genug macht wie hier genannt
(im durchgestrichener Text, durchgestrichen wegen etwas anderem, später noch in diesem Posting erwähnt) ?
Java: Concurrency inside ActionListener.actionPerformed - Stack Overflow
falls sich wer angesprochen fühlt, verlasst ihr euch darauf oder alternativ synchronized in jedem Listener der allgemeine Daten für andere Threads ändert
(bei denen nicht die normalen Probleme bestehen die synchronized eh erfordern, wie List.add() usw., sondern etwa boolean, viele volatile auch noch Variante…) ?
die zweite Seite dazu ist, im eigenen Thread alle Änderungen per Synchronisation zur Verfügung zu stellen (deswegen im Link durchgestrichener Text),
damit der EDT diese Änderungen sieht
hier ein Beispielprogramm aus dem Forum:
der Themensteller hat das natürlich überhaupt nicht auf dem Plan, meine Wenigkeit nicht,
und immerhin auch 4 weitere Forum-Nutzer, von denen einige eigenen mehr oder weniger veränderten Code posten, aber niemand verwendet volatile oder synchronized,
was ist davon zu halten?
hier das GamePanel aus dem Quaxli-Spiele-Tutorial
[spoiler]```public class GamePanel extends JPanel implements Runnable, KeyListener, ActionListener{
private static final long serialVersionUID = 1L;
JFrame frame;
long delta = 0;
long last = 0;
long fps = 0;
long gameover = 0;
Heli copter;
Vector<Sprite> actors;
Vector painter;
boolean up;
boolean down;
boolean left;
boolean right;
boolean started;
int speed = 50;
Timer timer;
BufferedImage[] rocket;
BufferedImage[] explosion;
BufferedImage background;
SoundLib soundlib;
public static void main(String[] args){
new GamePanel(800,600);
}
public GamePanel(int w, int h){
this.setPreferredSize(new Dimension(w,h));
this.setBackground(Color.BLUE);
frame = new JFrame("GameDemo");
frame.setLocation(100,100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.addKeyListener(this);
frame.pack();
frame.setVisible(true);
Thread th = new Thread(this);
th.start();
}
private void doInitializations() {
last = System.nanoTime();
gameover = 0;
BufferedImage[] heli = loadPics("pics/heli.gif", 4);
rocket = loadPics("pics/rocket.gif",8);
background = loadPics("pics/background.jpg",1)[0];
explosion = loadPics("pics/explosion.gif",5);
actors = new Vector<Sprite>();
painter = new Vector<Sprite>();
copter = new Heli(heli,400,300,100,this);
actors.add(copter);
soundlib = new SoundLib();
soundlib.loadSound("bumm", "sound/boom.wav");
soundlib.loadSound("rocket", "sound/rocket_start.wav");
soundlib.loadSound("heli", "sound/heli.wav");
createClouds();
timer = new Timer(3000,this);
timer.start();
started = false;
}
private void createClouds(){
BufferedImage[] bi = loadPics("pics/cloud.gif", 1);
for(int y=10;y<getHeight();y+=50){
int x = (int)(Math.random()*getWidth());
Cloud cloud = new Cloud(bi,x,y,1000,this);
actors.add(cloud);
}
}
public void createExplosion(int x, int y){
ListIterator<Sprite> it = actors.listIterator();
it.add(new Explosion(explosion,x,y,100,this));
soundlib.playSound("bumm");
}
private void createRocket(){
int x = 0;
int y = (int)(Math.random()*getHeight());
int hori = (int)(Math.random()*2);
if(hori==0){
x = -30;
}else{
x = getWidth()+30;
}
Rocket rock = new Rocket(rocket,x,y,100,this);
if(x<0){
rock.setHorizontalSpeed(100);
}else{
rock.setHorizontalSpeed(-100);
}
ListIterator<Sprite> it = actors.listIterator();
it.add(rock);
soundlib.playSound("rocket");
}
@Override
public void run() {
while(frame.isVisible()){
computeDelta();
if(isStarted()){
checkKeys();
doLogic();
moveObjects();
cloneVectors();
}
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
}
}
@SuppressWarnings("unchecked")
private void cloneVectors(){
painter = (Vector<Sprite>) actors.clone();
}
private void moveObjects() {
for(ListIterator<Sprite> it = actors.listIterator();it.hasNext();){
Sprite r = it.next();
r.move(delta);
}
}
private void doLogic() {
for(ListIterator<Sprite> it = actors.listIterator();it.hasNext();){
Sprite r = it.next();
r.doLogic(delta);
if(r.remove){
it.remove();
}
}
for(int i = 0;i < actors.size();i++){
for(int n = i+1; n<actors.size(); n++){
Sprite s1 = actors.elementAt(i);
Sprite s2 = actors.elementAt(n);
s1.collidedWith(s2);
}
}
if(copter.remove && gameover==0){
gameover = System.currentTimeMillis();
}
if(gameover>0){
if(System.currentTimeMillis()-gameover>3000){
stopGame();
}
}
}
private void startGame(){
doInitializations();
setStarted(true);
soundlib.loopSound("heli");
}
private void stopGame(){
timer.stop();
setStarted(false);
soundlib.stopLoopingSound();
}
private void checkKeys() {
if(up){
copter.setVerticalSpeed(-speed);
}
if(down){
copter.setVerticalSpeed(speed);
}
if(right){
copter.setHorizontalSpeed(speed);
}
if(left){
copter.setHorizontalSpeed(-speed);
}
if(!up&&!down){
copter.setVerticalSpeed(0);
}
if(!left&&!right){
copter.setHorizontalSpeed(0);
}
}
private void computeDelta() {
delta = System.nanoTime() - last;
last = System.nanoTime();
fps = ((long) 1e9)/delta;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background, 0, 0, this);
g.setColor(Color.red);
g.drawString("FPS: " + Long.toString(fps), 20, 10);
if(!started){
return;
}
for (ListIterator<Sprite> it = painter.listIterator(); it.hasNext();) {
Sprite r = it.next();
r.drawObjects(g);
}
}
private BufferedImage[] loadPics(String path, int pics){
BufferedImage[] anim = new BufferedImage[pics];
BufferedImage source = null;
URL pic_url = getClass().getClassLoader().getResource(path);
try {
source = ImageIO.read(pic_url);
} catch (IOException e) {}
for(int x=0;x<pics;x++){
anim[x] = source.getSubimage(x*source.getWidth()/pics, 0, source.getWidth()/pics, source.getHeight());
}
return anim;
}
public boolean isStarted() {
return started;
}
public void setStarted(boolean started) {
this.started = started;
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_UP){
up = true;
}
if(e.getKeyCode()==KeyEvent.VK_DOWN){
down = true;
}
if(e.getKeyCode()==KeyEvent.VK_LEFT){
left = true;
}
if(e.getKeyCode()==KeyEvent.VK_RIGHT){
right = true;
}
}
@Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_UP){
up = false;
}
if(e.getKeyCode()==KeyEvent.VK_DOWN){
down = false;
}
if(e.getKeyCode()==KeyEvent.VK_LEFT){
left = false;
}
if(e.getKeyCode()==KeyEvent.VK_RIGHT){
right = false;
}
if(e.getKeyCode()==KeyEvent.VK_ENTER){
if(!isStarted()){
startGame();
}
}
if(e.getKeyCode()==KeyEvent.VK_ESCAPE){
if(isStarted()){
stopGame();
}else{
frame.dispose();
}
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void actionPerformed(ActionEvent e) {
if(isStarted() && e.getSource().equals(timer)){
createRocket();
}
}
}```[/spoiler]
auch nix synchronisiert…,
funktioniert freilich auch so bestens, solange nur der dämliche JVM-Optimierer keinen Code klaut besteht ja im Grunde keine Gefahr anscheinend,
weiter unten noch mehr Gemecker dazu 
eine Frage dazu noch genauer gestellt, falls wer was sagen möchte:
im GamePanel gibt es
{```
alternativ die Würfel-Objekte aus dem Kniffel-Programm
werden wirklich die kompletten Objekte in einen lokalen Speicher gelegt und bekommen dann womöglich andere Belegung der internen Attribute wie boolean?
wie sonst..
hilft volatile auf das eigene Attribut frame (im GamePanel)?,
oder achtet das nur darauf, ob evtl. ein anderes Objekt in das Attribut gelegt wird?
wenn man sich das JFrame in eine lokale Variable holt (etwa vor langer Game-Schleife), was sich ja allgemein als Cache etwas anbietet,
dann ist das Attribut mit volatile oder nicht eh ausgeschaltet..
ohne synchronized ginge also gar nichts, wie soll man das aber bei einer Schleifenbedingung `while (frame.isVisible())`formulieren?
außerhalb der Schleife wäre nur ein großes synchronized über gesamte Zeit,
innerhalb der Schleife, dann nicht synchronisiert vor Prüfen der Bedingung, obwohl vielleicht am Ende des letzten Schleifendurchlaufs.. in dieser Konstellation hier
braucht es idealerweise eine Hilfsmethode, die synchronisiert und `while (checkVisible())` ?
das sind Auswüchse.., nun ja
---------
bei diesem Thema hier
[java - While loop not ending when flag changed in different thread - Stack Overflow](http://stackoverflow.com/questions/11595868/while-loop-not-ending-when-flag-changed-in-different-thread)
ein ähnliches Problem wie Programm von Marco13 hier und grün-Antwort wiederum
> You need to declare the flag volatile, otherwise the compiler can optimize your code and skip the reads of the flag.
was ist das nur für eine Optimierung, die denkbar kompliziert herausfindet, was alles in einem Thread passieren kann,
dabei offensichtlich auch sieht, dass das Flag durchaus auf true gesetzt wird, aber keine Rückmeldung an User für wichtig erachtet..
den JVM-Optimierer ausstellen ist keine Option, aber kann man nicht einzeln sagen dass bitte auf Verzicht von Code verzichtet werden soll?!
wenn er verzichtbar wäre, dann wäre er ja auch nicht geschrieben worden,
und wenn der Code drin bleibt, dann arbeitet er auch,
was für ein Optimier-Feature..
hilfreich wäre ein Log zumindest nach einem Test-Lauf welches anzeigt, welcher Code irgendwann mal (temporär) wegoptimiert wurde..