【问题标题】:Synchronized and the scope of visibility同步和可见范围
【发布时间】:2013-01-15 00:06:35
【问题描述】:

我一直在阅读有关 Java 并发性的内容,但忘记了使用相同锁的两个线程中的同步块也会影响变量的可见性,即使它们没有被定义为“易失性”。如果我有这样的代码

Object lock = new Object();
boolean a = false, b = false, c = false;

void threadOne() {

   a = true;
   synchronized(lock) {
      b = true;
   }
   c = true;

}

void threadTwo() {

   while (true) {
      synchronized(lock) {
         if (a && b && c) break;
      }
   } 

}

...而threadOne和threadTwo会被不同的线程调用:

  1. 是否保证代码会跳出while循环?

  2. 如果我们从方程中删除变量 c 会怎样?我想知道是否只有 b 保证在 threadTwo 中可见,因为它在同步块内。

【问题讨论】:

    标签: java concurrency synchronized java-memory-model


    【解决方案1】:

    是否保证代码会跳出while循环?

    没有。 Java 内存模型是根据“happens before”关系定义的:

    两个动作可以通过happens-before关系排序。如果一个动作发生在另一个动作之前,那么第一个动作对第二个动作可见并在第二个动作之前排序。

    规范接着说:

    如果动作 x 与后续动作 y 同步,那么我们也有 hb(x, y)。

    hb 代表发生在之前,并且

    监视器 m 上的解锁操作与 m 上的所有后续锁定操作同步(其中“后续”根据同步顺序定义)。

    还要注意:

    如果 hb(x, y) 和 hb(y, z),则 hb(x, z)。

    因此,在您的示例中,b 周围的 synchronized(lock) 将为以下读取建立发生前的关系,因此b 的值保证在也使用synchronized(lock) 的其他线程中可见.明确地,

    hb(write to b in threadOne, unlock in threadOne) AND 
    hb(unlock in threadOne, lock in threadTwo) AND 
    hb(lock in threadTwo, read from a in threadTwo) IMPLIES 
    hb(write to b in threadOne, read from b in threadTwo) 
    

    同样,a 将保证对其他线程可见。明确地,

    hb(write to a in threadOne, lock in threadOne) AND 
    hb(lock in threadOne, unlock in threadOne) AND 
    hb(unlock in threadOne, lock in threadTwo) AND 
    hb(lock in threadTwo, read a in threadTwo) IMPLIES 
    hb(write to a in threadOne, read a in threadTwo). 
    

    c 的写入和后续读取没有发生前的关系,因此,根据规范,c 的写入不一定对threadTwo 可见。

    如果我们从方程中删除变量 c 会怎样?我想知道是否只有 b 保证在 threadTwo 中可见,因为它在同步块内。

    是的,见上文。

    【讨论】:

      【解决方案2】:

      假设每个线程共享您在问题中定义的(不完整)类的相同实例:

      是否保证代码会跳出while循环?

      在实践中,是的。锁只在 threadOne 方法中设置 b 的时间很短。 threadTwo 中有足够的上下文切换,以便 threadOne 能够执行同步块。 “在实践中”的意思是:在极不可能的情况下(以及实施不佳的 JVM 线程),threadOne 可能会被排除在同步块之外,而 threadTwo 继续为 if 检查重新获取同步锁。 (事实上,我挑战任何人来制作一个 OPs 场景没有完成的工作示例)。

      如果我们从方程中删除变量 c 会怎样?我想知道如果 只有 b 保证在 threadTwo 中可见,因为它在里面 同步块。

      一样。实际上,是的。

      为了获得额外的荣誉(挑战),找到一个执行以下代码的 JVM,这样它就不会终止:

      public class SyncTest {
      
        public static void main(String args[]) throws Exception {
      
                final Shared s = new Shared();
                Thread t1 = new Thread () { public void run() { s.threadOne(); } };
                Thread t2 = new Thread () { public void run() { s.threadTwo(); } };
      
                t2.start();
                t1.start();
        }
      }
      
      class Shared {
      
        Object lock = new Object();
        boolean a = false, b = false, c = false;
      
        void threadOne() {
          a = true;
          synchronized(lock) {
             b = true;
          }
          c = true;
        }
      
        void threadTwo() {
          while (true) {
            synchronized(lock) {
               if (a && b && c) break;
            }
          }
        }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-08-24
        • 2014-04-05
        • 2017-10-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多