Нить не может быть вызвана - PullRequest
0 голосов
/ 20 марта 2020
class client
{
    static int data = 0;
    public static void main(String[] args)
    {
        new Thread(new Runnable() 
        {
            @Override
            public void run()
            {
                while(true)
                {
                    //System.out.print("");
                    if(data == 1) {System.out.println("GOTCHA");}
                }
            }
        }).start();
        Scanner sc = new Scanner(System.in);
        while(true)
        {
            data = sc.nextInt();
        }
    }
}

Я не понимаю, почему это не работает, когда я печатаю 1. и есть забавная ситуация, что, если я удаляю комментарий (System.out.print ("")), это работает. Я могу сделать это по-другому, как метод обратного вызова, только я хочу, чтобы он не работал.

1 Ответ

1 голос
/ 20 марта 2020

Краткая версия заключается в том, что совместно используемые переменные должны ЛИБО быть объявлены как volatile ИЛИ доступ / обновление переменных должно выполняться с использованием соответствующего механизма синхронизации. Подходящим механизмом синхронизации может быть:

  • Использование примитивных мониторов; т.е. synchronized блоки или методы с одним и тем же целевым объектом.

  • Использование Lock.acquire и Lock.release для одного и того же объекта блокировки.

  • Что-то еще с соответствующими происходит до отношений. (Не беспокойтесь об этом случае. Это сложно. Но если хотите, прочитайте о Java Модель памяти.)

В любом случае, если два потока совместно используют (энергонезависимая) переменная без соответствующей синхронизации, тогда одному потоку не гарантируется 1 , чтобы увидеть значение, записанное другим потоком. Это то, что происходило с вашим примером. Дочерний поток никогда не видит результаты записи родительского потока.

Это нормальное поведение с многопоточностью в Java. И одна из причин, почему параллельное программирование в Java является хитрым.


1 - В некоторых случаях данные будут видны, а в других - нет. Это может зависеть от версии Java, операционной системы, аппаратной платформы, отладки или нет, а также от различных других вещей. Существует как минимум две возможные причины проблем с видимостью. 1) Это часто связано с проблемами кэширования памяти; например, изменения, сделанные одним потоком, не сбрасываемым в основную память, чтобы другой поток мог их видеть. 2) В качестве альтернативы, это (по крайней мере, в теории) может быть связано с JIT-компилятором, оптимизирующим выборки из памяти. Чтобы точно понять, что происходит, вам нужно проанализировать нативный код, генерируемый JIT-компилятором. Но в любом случае, эти поведения разрешены моделью памяти Java ... если требуемый происходит до того, как отношения не существуют.

...