简体   繁体   English

Java发生在关系之前

[英]Java happens-before relationship

Although there are a lot of posts on SO and elsewhere about the happens-before relationship, I am having a surprisingly hard time finding a definitive answer to my question. 虽然SO和其他地方有很多关于之前发生过的关系的帖子,但我很难找到对我的问题的确切答案。

Consider the two Java threads: 考虑两个Java线程:

initially, flag == false and data == 0 最初, flag == falsedata == 0

T1 T1

data = 42;
synchronized(m) {
  flag = true;
}

T2 T2

boolean f;
synchronized(m) {
  f = flag;
}
if (f) {
  int x = data;
}

According to the code above, I believe f could either be assigned the value true or false , there is no guaruntee. 根据上面的代码,我相信f可以被赋值为truefalse ,没有guaruntee。 Is this correct? 它是否正确?

Now, if the two synchronized statements were changed to synchronized(flag) , I think the instruction flag = true will always happen before the instruction f = flag , and thus f will always be assigned the value true . 现在,如果两个synchronized语句被更改为synchronized(flag) ,我认为指令flag = true将始终发生在指令f = flag ,因此f将始终被赋值为true Is this correct? 它是否正确?

No, synchronized make no guarantees about which Thread gets there first. 不,同步不保证首先到达哪个Thread In only guarantees that more that one Thread cannot access the synchronized block at a time. 仅保证多一个Thread不能一次访问同步块。

Think of a synchronized block as a room with a lock on the door. synchronized块视为门上有锁的房间。 We have no idea who will get to the door first, but once they do they go in and lock the door. 我们不知道谁会首先到达门口,但一旦他们这样做,他们就会进门并锁上门。

Other people must wait until the person in the room is ready to leave and unlocks the door. 其他人必须等到房间里的人准备离开并解锁门。 Once that happens everyone races to get in the door again. 一旦发生这种情况,每个人都会再次参加比赛。

It all depends on the order in which you set your Thread s off. 这一切都取决于您关闭Thread的顺序。 But even then there are no guarantees as the JVM may suspend Thread s and Thread s yield to one-another randomly. 但即便如此,也没有任何保证,因为JVM可能会随机地暂停ThreadThreadyield In the analogy - the guy in the lead to get to the door might trip on a banana peel. 在类比中 - 领先到门的人可能会在香蕉皮上绊倒。 No likely, but always possible. 不太可能,但总是可能的。

If you want to have guarantees then you need to wait / notify - so that the reading thread checks the flag , and if it's false , suspends itself in a loop. 如果你想要保证,那么你需要wait / notify - 以便读取线程检查flag ,如果它是false ,则在循环中挂起自己。

The writing thread then sets the flag and notifies the lock monitor which wakes the reading thread. 写入线程然后设置flag并通知锁定监视器唤醒读取线程。

Here is an example using the Lock and Condition api from Java 5. I'm not saying that you have to use that in preference to synchronized and wait / notify - it's just an example I had lying around that I adapted. 下面是一个使用Java 5中的LockCondition api的示例。我并不是说你必须优先使用它来synchronizedwait / notify - 这只是我躺在我适应的一个例子。

The Reader acquires the lock and then checks the ready flag in a loop. Reader获取lock ,然后在循环中检查ready标志。 If the flag is false it await s on the condition. 如果该标志为falseawait该条件。 This atomically releases the lock and suspends the Thread . 这会以原子方式释放lock并挂起Thread

The Writer meanwhile acquires the lock and sets the data and the ready flag. Writer同时获取lock并设置dataready标志。 It then calls signalAll and releases the lock . 然后它调用signalAll并释放lock

This wakes the Reader which then reads the ready as true and proceeds to the print statement. 这会唤醒Reader ,然后读取readytrue并继续执行print语句。

The output will always be 42 (never -1 ). 输出将始终为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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM