System.out таинственным образом исчезает, хотя код/строка выполняется

Итак, я протестировал этот код на java 8, 11 и 14, все они имеют одинаковый результат. Это плохая практика и нереалистичный сценарий, но я хотел бы понять внутренности JVM, из-за которых это происходит.

Если вы запустите этот код, вы заметите, что все, кроме самой части печати system.out.println внутри, выполняется. В какой-то момент с немного другой версией Java мне удалось распечатать ее, изменив игру слишком изменчиво, но даже это сейчас не работает.

Пожалуйста, хотя бы проверьте код, прежде чем утверждать, что он просто блокирует переменные или использует кеш, это не так, если выполняется, и все внутри него работает, кроме самой части печати.

public class Main {
    public static void main(String[] args) {
        TestClass t = new TestClass();
        System.out.println("Starting test");
        new MyRunnable(t).start();
        while (true)
            t.testUpdate(System.currentTimeMillis());
    }
}
public class MyRunnable extends Thread {

    private TestClass t;

    public MyRunnable(TestClass t) {
        this.t = t;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(500L);
            t.setPlay(true);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class TestClass {
    private boolean play = false;
    private long lastUpdate = 0;
    private long updateRate = 2000;
    private boolean hasSysoBeenHit = false;

    public void testUpdate(long callTime) {
        System.out.println(play);
        System.out.println((callTime-lastUpdate));
        if (this.play && ((callTime-lastUpdate) >= updateRate)) {
            System.out.println("Updating! " + (hasSysoBeenHit = true));

            this.lastUpdate = callTime;
        }
        System.out.println("hasbeenhit? " + hasSysoBeenHit);
    }

    public void setPlay(boolean t) {
        System.out.println("Starting game...");
        this.play = t;
    }
}

person Agammar Kekker    schedule 19.01.2021    source источник
comment
Поиск в Интернете объяснил бы это довольно легко. Ну, может быть, это и не просто, но вы бы нашли причину довольно быстро. Это связано с тем, что JVM собирает вывод потоков println. На самом деле нет способа обойти это, это просто способ реализации JVM. Если вы хотите сделать это, вам нужен другой способ вернуть данные. Взгляните на stackoverflow.com/questions/9467759/   -  person Fullslack    schedule 19.01.2021
comment
Какая часть печати не выполняется? Я не вижу проблем, кроме того факта, что play должен быть volatile   -  person areus    schedule 19.01.2021
comment
Почему только Обновление! пропускается в этом случае? все остальное продолжает печатать этим методом, все отпечатки из одного и того же потока, кроме одного. Он не устарел и не разделяет буфер, так как все остальное работает. Кроме того, мне нужен тот факт, почему он должен быть изменчивым для печати (у меня даже тогда это не работает?).   -  person Agammar Kekker    schedule 20.01.2021


Ответы (1)


Ваш код страдает от гонки данных в поле TestClass.play: к этому полю обращаются 2 потока, и по крайней мере один из них выполняет запись. На это уже указывает @aerus.

Если вы сделаете поле изменчивым, гонка данных будет удалена. Ищите правило volatile переменной в модели памяти Java.

Я бы также переместил логику проверки воспроизведения в начало метода testUpdate:

public void testUpdate(long callTime) {
    if(!play)return;
    ... 
person pveentjer    schedule 21.01.2021
comment
Вы тестировали код...? И его улучшение не является целью этого вопроса. В любом случае, полное время (true) бесконечно не должно существовать для галочки в игре. Я знаю, что такое volatile, но если вы действительно запустите этот код, вы увидите, что if() не может получить к нему доступ. На самом деле, другой поток обращается к нему только один раз, через 500 мс, не говоря уже о воспроизведении печати, времени и hasbeenhit all print fine после 500 мс, побочный эффект в печати (Updating + (hassysobeenhit = true)) превращает это логическое значение в true и вы можете это увидеть. До сих пор нет обновления! печатать однако. - person Agammar Kekker; 22.01.2021