【问题标题】:Are empty synchronized blocks optimized out by Java compiler?Java编译器是否优化了空的同步块?
【发布时间】:2013-08-06 00:56:14
【问题描述】:

假设在我的代码中某处我写了一个空的synchronized 块:

synchronized(obj){
   //No code here
}

所以由于同步块不包含任何代码,JIT 编译器是否会通过不锁定 obj 来优化它,因为它没有用处?

Java 编译器也有类似的技巧,比如锁粗化,但是这个同步块也会被优化掉吗?

编辑:

根据 assylias 的观点,

synchronized(new Object()){
   //empty block
}

JIT 编译器现在是否能够优化这一点,因为我使用的对象不会转义我的方法?

【问题讨论】:

  • @tbodt 如果他可以,他不会问...请告诉他如何“尝试”
  • 我只是把那个代码放到一个文件里,反编译了class文件,虽然是空的,但同步块还在。
  • @tbodt 不能证明任何事情。它可能会被 JIT 删除。另一个编译器/JVM 的行为可能会有所不同,等等。
  • @Tala 恕我直言,了解编译器在后台做什么会让你成为更好的程序员。
  • @tbodt 查看字节码很少可以证明任何事情。只是不要打扰它。

标签: java locking compiler-optimization


【解决方案1】:

这不能基于 Java 内存模型语义进行优化。锁获取-释放操作可能被其他东西替换,但即使是一个空的synchronized 块也会对获取相同锁的其他线程所采取的操作的可见性产生影响。

具体来说,可以保证一个线程在释放锁之前完成的所有写操作在另一个线程获得相同的锁后对它都是可见的

关于您的编辑

这是一个非常不同的情况:在一个对象上获得了一个锁,可以通过逃逸分析证明没有其他线程能够获取它。在这种情况下,synchronized 块的内容是什么并不重要:该点仅在使用的锁中。代码可以看起来像您发布的那样,甚至是这样的:

Object o = new Object();
synchronized(o) { 
   // any operations you like, as long as they don't let o escape the method scope
}

这可以通过称为锁省略的转换来处理:JVM 可以假装它从未见过synchronized 块。这是因为 JMM 语义只涉及获取同一个锁的情况。

【讨论】:

  • @assylias 我也会在问题中补充一点:)很好,因为在这种情况下也不会有可见性保证。
  • @assylias 你和我的答案变得难以区分:)
  • @MarkoTopolnik 我认为这是一种恭维!
  • 所以,如果我们使用synchronized(mutex){ },其中mutex 是一个共享变量(类的一个字段),我们可以安全地假设此锁定提供的可见性保证,对吧?我的意思是,没有lock elision 发生
  • @Alupkers 另一个线程获取相同的锁并获得保证,或者它没有也没有获得它们。只要 JIT 编译器可以证明另一个线程不可能获得相同的锁,它就可以从它输出的机器代码中删除它。如果不能证明,就会输出相应的内存栅栏。
猜你喜欢
  • 2014-04-18
  • 1970-01-01
  • 1970-01-01
  • 2018-07-08
  • 2018-07-24
  • 2014-05-23
  • 2011-03-18
  • 1970-01-01
  • 2010-11-22
相关资源
最近更新 更多