Java发生在关系之前

and*_*ert 3 java synchronization

虽然SO和其他地方有很多关于之前发生过的关系的帖子,但我很难找到对我的问题的确切答案.

考虑两个Java线程:

最初,flag == false和data == 0

T1

data = 42;
synchronized(m) {
  flag = true;
}
Run Code Online (Sandbox Code Playgroud)

T2

boolean f;
synchronized(m) {
  f = flag;
}
if (f) {
  int x = data;
}
Run Code Online (Sandbox Code Playgroud)

根据上面的代码,我相信f可以分配价值,true或者false没有保证.它是否正确?

现在,如果将两个synchronized语句更改为synchronized(flag),我认为指令flag = true将始终在指令之前发生f = flag,因此f将始终为该指令赋值true.它是否正确?

Bor*_*der 6

不,同步不保证Thread首先到达那里.仅保证一次Thread不能访问同步块.

把一个synchronized街区想象成一个带门锁的房间.我们不知道谁会首先到达门口,但一旦他们这样做,他们就会进门并锁上门.

其他人必须等到房间里的人准备离开并解锁门.一旦发生这种情况,每个人都会再次参加比赛.

这一切都取决于你Thread关闭的顺序.但即使这样,也没有任何保证,因为JVM可能会随机暂停Threads和Threads yield.在类比中 - 领先到门的人可能会在香蕉皮上绊倒.不太可能,但总是可能的.

如果你想要保证,那么你需要wait/ notify- 以便读取线程检查flag,如果是false,则在循环中挂起它自己.

写入线程然后设置flag并通知锁定监视器唤醒读取线程.

下面是使用的例子Lock,并Condition从Java API 5.我不是说你必须要使用优先于synchronized和wait/ notify-这只是一个例子,我已经躺在附近,我适应.

的Reader获取lock,然后检查ready标志在一个循环.如果标志是false其awaitS ON的状态.这原子地释放lock并暂停Thread.

的Writer同时获取lock和设置data和ready标志.然后它调用signalAll并释放lock.

这会唤醒Reader然后读取readyas true并继续执行print语句.

输出将始终为42(从不-1).

public class App {

    static volatile boolean ready = false;
    static volatile int data = -1;

    private static class Reader implements Runnable {

        private final Lock lock;
        private final Condition condition;

        public Reader(Lock lock, Condition condition) {
            this.lock = lock;
            this.condition = condition;
        }

        @Override
        public void run() {
            lock.lock();
            try {
                while (!ready) {
                    try {
                        condition.await();
                    } catch (InterruptedException ex) {
                        //oh well
                    }
                }
                System.out.println(data);
            } finally {
                lock.unlock();
            }
        }
    }

    private static class Writer implements Runnable {

        private final Lock lock;
        private final Condition condition;

        public Writer(Lock lock, Condition condition) {
            this.lock = lock;
            this.condition = condition;
        }

        @Override
        public void run() {
            lock.lock();
            try {
                data = 42;
                ready = true;
                condition.signalAll();
            } finally {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        final ExecutorService executorService = Executors.newFixedThreadPool(2);
        final Lock lock = new ReentrantLock();
        final Condition condition = lock.newCondition();
        executorService.execute(new Reader(lock, condition));
        executorService.execute(new Writer(lock, condition));
        executorService.shutdown();
        executorService.awaitTermination(1, TimeUnit.DAYS);
    }
}
Run Code Online (Sandbox Code Playgroud)