相关Java will synchronized block if changed?

 public class TestConcurrentTwo {
     public static void main(String[] args) {

         class lock {
             public Object lockObj = new Object();
             int protectedValue = 0;
         }
         lock a = new lock();

         Thread t = new Thread(() -> {
             try {
                 synchronized (a.lockObj) {
                     System.out.println("from first block start");
                     System.out.println(a.protectedValue);
                     a.lockObj = new Object();
                     Thread.sleep(1000);
                     System.out.println(a.protectedValue);
                     System.out.println("from first block done");
                 }
             } catch (InterruptedException x) {}
         });
         t.start();
         try {
             Thread.sleep(100);
         } catch (InterruptedException x) {}

         synchronized (a.lockObj) {
             System.out.println("from second block start");
             a.protectedValue++;
             System.out.println("from second block done");
         }

         System.out.println(a.protectedValue);
     }
 }


输出:

from first block start
0
from second block start
from second block done
1
1
from first block done


在相关的答案中,它们都保留了原始参考,因此应该阻塞第二个块,直到第一个块完成为止。

但是,一旦a.lockObj从第一个程序段更改起,第二个程序段便确实进行了。为什么?

最佳答案

您正在创建两个对象,因此我们将其命名为参考:


在字段初始化程序中创建的ObjA
sleep(1000)之前的行中创建的ObjB


线程中的synchronized (a.lockObj)块锁定在ObjA上。

由于启动线程后已具有sleep(100),因此在主线程到达其a.lockObj块时,该线程将已更改synchronized (a.lockObj)以引用ObjB,因此它将锁定在另一个对象上。

作为另一个对象,该代码将不会阻塞。

提示:锁位于对象上,而不是引用变量上。

07-28 00:19