【问题标题】:Same bytecode for method with or without synchronized keyword in method signature方法签名中带或不带同步关键字的方法的相同字节码
【发布时间】:2018-10-19 12:30:27
【问题描述】:

对于以下 2 个类具有相同的 Java 字节码。

java 版本:

java 版本 "1.8.0_181" Java(TM) SE Runtime Environment (build 1.8.0_181-b13) Java HotSpot(TM) 64 位服务器 VM(内部版本 25.181-b13,混合模式)

javac 和 javap 版本:

1.8.0_181

我的怀疑是

  1. synchronized 关键字的方法不应该有不同的字节码,正如我们在 synchronized 块 中看到的那样有monitorentermonitorexit,或者让我们假设我不应该混合同步块同步 方法然后

  2. JVM 如何以不同方式处理这两种方法?

    public class MySingleton1 {
    
    private MySingleton1() {}
    
    private static MySingleton1 ourInstance;
    
    public static MySingleton1 getInstance() {
        if (ourInstance == null) {
            ourInstance = new MySingleton1();
        }
        return ourInstance;
    }
    }
    

    public class MySingleton2 {
    
    private MySingleton2() {}
    
    private static MySingleton2 ourInstance;
    
    public static synchronized MySingleton2 getInstance() {
        if (ourInstance == null) {
            ourInstance = new MySingleton2();
        }
        return ourInstance;
    }
    }
    

字节码如下:

$javac MySingleton1.java
$javap -c MySingleton1
$javac MySingleton2.java
$javap -c MySingleton2

各个文件的字节码:

Compiled from "MySingleton1.java"
public class MySingleton1 {
  public static MySingleton1 getInstance();
    descriptor: ()LMySingleton1;
    Code:
       0: getstatic     #2                  // Field ourInstance:LMySingleton1;
       3: ifnonnull     16
       6: new           #3                  // class MySingleton1
       9: dup
      10: invokespecial #4                  // Method "<init>":()V
      13: putstatic     #2                  // Field ourInstance:LMySingleton1;
      16: getstatic     #2                  // Field ourInstance:LMySingleton1;
      19: areturn
}

Compiled from "MySingleton2.java"
public class MySingleton2 {
  public static synchronized MySingleton2 getInstance();
    descriptor: ()LMySingleton2;
    Code:
       0: getstatic     #2                  // Field ourInstance:LMySingleton2;
       3: ifnonnull     16
       6: new           #3                  // class MySingleton2
       9: dup
      10: invokespecial #4                  // Method "<init>":()V
      13: putstatic     #2                  // Field ourInstance:LMySingleton2;
      16: getstatic     #2                  // Field ourInstance:LMySingleton2;
      19: areturn
}

我只是想增加我对 java w.r.t 的理解。字节码。

如果我的方法有误或问题太琐碎,请以 cmets 的身份告诉我。

欢迎任何与文档相关的参考,但以下内容除外:

https://en.wikipedia.org/wiki/Java_bytecode

https://en.wikipedia.org/wiki/Java_bytecode_instruction_listings

http://www.cnblogs.com/richaaaard/p/6214929.html

【问题讨论】:

  • 使用$javap -v MySingleton2 代替$javap -c MySingleton2。这告诉我:public static synchronized so.MySingleton2 getInstance(); descriptor: ()Lso/MySingleton2; flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED

标签: java bytecode synchronized


【解决方案1】:

方法上的synchronized 修饰符被编译到方法头中的 ACC_SYNCHRONIZED 标志中。它不影响生成的字节码指令;进入和退出监视器的代码由 JVM 在看到该标志时隐式添加。

请参阅JVM specification,了解方法标头中标志的完整列表及其含义。

【讨论】:

  • 谢谢@yole,是否可以通过字节码或其他方式检查这些标志?我想了解的是 JVM 如何知道该标志存在于方法级别?我假设 JVM 只有用户的字节码,字节码中是否还有其他不可见/不可访问的内容(如元数据)?
  • dkb 每个包含同步标志的方法都有一个标志位域。这与 JVM 知道该方法是公共的还是私有的、严格的还是静态的等等的方式是一样的。
  • .class文件除了字节码指令外还包含很多数据。有关格式的详细说明,请参阅链接文档。 JVM 在运行时可以访问和使用所有这些信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-05
  • 1970-01-01
  • 2010-11-04
  • 1970-01-01
  • 1970-01-01
  • 2014-10-24
  • 2019-06-12
相关资源
最近更新 更多