3

尽管在 SO 和其他地方有很多关于发生前关系的帖子,但我很难为我的问题找到明确的答案。

考虑两个 Java 线程:

最初,flag == false并且data == 0

T1

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

T2

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

根据上面的代码,我相信f要么被赋值,要么true没有false保证。这个对吗?

现在,如果将两条synchronized语句更改为synchronized(flag),我认为指令flag = true将始终发生在指令之前f = flag,因此f将始终被赋值true。这个对吗?

4

1 回答 1

6

不,同步不保证哪个Thread先到达那里。In 只保证一次Thread不能访问同步块。

把一个synchronized街区想象成一个门上有锁的房间。我们不知道谁会先到门口,但一旦他们进去,他们就会进去锁上门。

其他人必须等到房间里的人准备好离开并解锁门。一旦发生这种情况,每个人都争先恐后地再次进入大门。

这完全取决于您设置Thread关闭的顺序。但即便如此,也无法保证,因为 JVM 可能会随机地将Threads 和Threads挂起。yield在类比中 - 带头到门口的人可能会被香蕉皮绊倒。不可能,但总是可能的。

如果您想获得保证,那么您需要wait/ notify- 以便读取线程检查flag,如果是 ,则将false自身暂停在一个循环中。

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

这是一个使用 Java 5 中的Lockand Conditionapi 的示例。我并不是说您必须使用它来优先于synchronizedand wait/ notify- 这只是我在周围使用的一个示例。

Reader获取然后在循环中lock检查标志。ready如果标志是falseawait的条件。这以原子方式释放lock并暂停Thread.

同时Writer获取lock并设置dataready标志。然后它调用signalAll并释放lock.

这将唤醒Reader然后读取readyastrue并继续执行print语句。

输出将始终为42(never -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);
    }
}
于 2013-04-26T15:01:28.247 回答