Проблема с общей переменной между потоками в Java(11)

может быть, то, что я надеюсь выразить, не так ясно, первый случай - пример того, когда и как использовать volatile, И чтобы программа работала успешно, Нам нужно добавить volatile.

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

В первом примере типичный образец использования летучих

public static int num=1;

public static class MyThread extends Thread {
    // flag
    private boolean flag = false ;
    public boolean isFlag() { return flag;}
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) { e.printStackTrace();
        }
// change flag to true
        this.flag = true ;
        System.out.println("flag = " + flag);
        this.flag=true;
    }
}
// main
static void testWithOutVolatile(){
    MyThread t=new MyThread();
    t.start();
    while(true) {
        boolean is=t.flag;
        if (is) {
            System.out.println("run===== = ");
        }
    }
}

После запуска основной поток не найдет изменение флага, если только не используется volatile

Однако в примере поток 2 неожиданно получил смену флага, почему это произошло?

static int amb=0;
static void testSimple(){
    Thread t1=new Thread(()->{
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        amb++;
    });
    Thread t2=new Thread(()->{while(true) {
        if (amb == 0) {
            System.out.println("no");
        }
        if (amb != 0) {
            System.out.println("SUc");
            break;
        }
    }});
    t2.start();
    t1.start();
}

И после попытки я нахожу, если я удалю код

if (amb == 0) {
            System.out.println("no");
        }

он будет работать, как я и думал, thread2 не может получить изменение.

Спасибо за ответ, QwQ

Честно говоря, я не понимаю вашего вопроса, но позвольте мне прояснить несколько вещей. Чтобы переменная могла делиться своим состоянием между несколькими потоками в Java (в режиме реального времени), она должна быть изменчивой. Использование статических переменных: они совместно используются потоками, но изменения, сделанные в одном потоке, могут быть не сразу видны другому потоку, что создает впечатление наличия двух копий переменной. stackoverflow.com/questions/13582395/… xspdf.com/resolution/52087767.html

JCompetence 26.12.2020 11:16

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

Jirath Liu 26.12.2020 11:24

На самом деле, @SusanMustafa - это не совсем так, что так и должно быть volatile. Есть и другие способы. Например, используя synchronized соответствующим образом, или используя тип AtomicXxx, или используя поле final.

Stephen C 26.12.2020 12:03

@StephenC Да, Стивен, возможно, мой комментарий может создать впечатление, что это единственный способ, однако я привел пример переполнения стека для большего пояснения.

JCompetence 26.12.2020 12:05

@StephenC ххх, спасибо, понял причины, чувствует себя хорошо :P

Jirath Liu 26.12.2020 12:12
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
5
131
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Может быть, во втором случае оператор io обновляет буферную зону Thread

Thread t2=new Thread(()->{while(true) {
        System.out.println("no");
        if (amb != 0) {
            System.out.println("SUc");
            break;
        }
    }});

если я использую оператор io (Sout), он будет работать успешно.

Таким образом, я продолжаю находить причины в println. И я нахожу истинную причину

 public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

синхронизировано вызвало переключение потока

а с выключателем буферная зона нити была свободна,

поэтому thread2 читает новое значение

Другие вопросы по теме