Симуляция проблемы видимости поля в Java - PullRequest
2 голосов
/ 21 сентября 2019

Я изучал один из руководств по модели памяти Java и натолкнулся на концепцию field visibility, которая встречается в многопоточном программировании.Я попытался смоделировать то же самое, используя приведенный ниже код, однако, я вижу, в каждом потоке отражается последнее значение (в ReaderThread).

Ниже приведена полная программа.

РЕДАКТИРОВАТЬ После некоторого предложения использовать while (somevariable), я включил, но все еще получаю то же самое поведение.Я удалил sysout при чтении x

FieldVisibility.java

package com.example.threads.fieldvisibility;

public class FieldVisibility {

    private int x;

    private boolean condition;

    public FieldVisibility() {
        condition = true;
    }

    public void reader() {

        System.out.println("x in reader() is " + x);
    }

    public void writer() {
        x++;

    }

    public boolean getCondition() {
        return condition;
    }

    public void setCondition(boolean condition) {
        this.condition = condition;
    }
}

ReaderThread.java

package com.example.threads.fieldvisibility;

public class ReaderThread extends Thread {

    private FieldVisibility fv;

    public ReaderThread(FieldVisibility fv) {
        this.fv = fv;

    }

    @Override
    public void run() {

        while (fv.getCondition()) {

            System.out.println("It mean condition is true, which was set initially");

        }
        for (;;) {

        }
    }
}

WriterThread.java

package com.example.threads.fieldvisibility;

public class WriterThread extends Thread {

    private FieldVisibility fv;

    public WriterThread(FieldVisibility fv) {
        this.fv = fv;

    }

    @Override
    public void run() {

        fv.setCondition(false);
        for (;;) {

            fv.writer();
        }

    }
}

MainApp.java

package com.example.threads.fieldvisibility.main;

import com.example.threads.fieldvisibility.FieldVisibility;
import com.example.threads.fieldvisibility.ReaderThread;
import com.example.threads.fieldvisibility.WriterThread;

public class MainApp {

    public static void main(String[] args) throws InterruptedException {

        FieldVisibility fv = new FieldVisibility();

        ReaderThread rt = new ReaderThread(fv);
        WriterThread wt = new WriterThread(fv);

        wt.start();

        rt.start();

        Thread.sleep(999999999L);
    }
}

РЕДАКТИРОВАТЬ

Я добавил новую переменную condition в FieldVisibility, значения по умолчанию которой true.Затем я установил его значение на false в WriterThread, однако то же значение (false) все еще распространяется на ReaderThread, поэтому я все еще не могу имитировать его.

Оригинал Я ожидал, что в какое-то время ReaderThread не сможет "увидеть" последнее значение переменной x, но я видел каждый раз, когда запускаю ее, онадал те же результаты.Я даже работаю в режиме отладки, приостановив ReaderThread при непрерывном запуске WriterThread.Но это также не помешало ReaderThread иметь последние значения.Я ожидал, что мне нужно объявить переменную x как энергозависимую, чтобы ReaderThread мог прочитать последние значения x.

Может кто-нибудь помочь, как смоделировать концепцию field visibility или какие изменения мне нужнычто делать для этого?

Спасибо за помощь и заранее.

1 Ответ

1 голос
/ 21 сентября 2019

Ваш пример не работает, потому что System.out.println() использует общий ресурс (System.out), поэтому он будет синхронизироваться с другими использованиями того же ресурса.

Поэтому вы никогда не увидите результат, в которомодин поток использует старое значение другого.(* теоретически читатель может прочитать x между x++ и соответствующими System.out.println()

. Вот пример, где используется старое значение:

public class ThreadVisibility implements Runnable {

    private boolean stop = false;

    @Override
    public void run() {
        while (!stop);
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadVisibility test = new ThreadVisibility();
        Thread t = new Thread(test);
        t.setDaemon(true);
        System.out.println("Starting Thread");
        t.start();
        Thread.sleep(1000);
        System.out.println("Stopping Thread");
        test.stop = true;
        t.join(1000);
        System.out.println("Thread State: " + t.getState());
    }
}

Если вы запустите этот код, он покажет, что поток все еще работает в конце. Без t.setDaemon(true) виртуальная машина будет ожидать завершения потока, что никогда не произойдет.

Если вы прокомментируетеThread.sleep, тогда новый поток может завершить работу (по крайней мере, в моих тестах), но это не гарантировано.
Правильное решение этой проблемы - объявить stop volatile.
Или добавить барьер памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...