本机方法同步

时间:2013-05-31 01:04:23

标签: java synchronization

我有一个像这样定义的本机方法:

public static native int doSomething();

但是,此方法不是线程安全的。所以,我在其上放了一个synchronized关键字,所以它现在看起来像这样:

public static synchronized native int doSomething();

这似乎可以解决问题,但我不确定它是否确实存在。这有效吗?它是否实际上正确锁定了对方法的访问权限?

2 个答案:

答案 0 :(得分:5)

在阅读相关的JLS section后,JLS中没有任何内容禁止staticnative进入方法定义。根据{{​​3}}

  

方法级同步是隐式执行的,作为方法调用和返回的一部分(第2.18.8节)。同步方法在运行时常量池的method_info结构(第4.6节)中通过ACC_SYNCHRONIZED标志区分,该标志由方法调用指令检查。当调用设置了ACC_SYNCHRONIZED的方法时,执行线程进入监视器,调用方法本身,并退出监视器,无论方法调用是正常还是突然完成。在执行线程拥有监视器期间,没有其他线程可以输入它。如果在调用synchronized方法期间抛出异常并且synchronized方法不处理异常,则在异步从同步方法中重新抛出之前,将自动退出该方法的监视器。

因此,生成的字节码没有任何monitorentermonitorexit指令,就像synchronized块一样。在这种情况下,唯一生成的是invokestatic,以便调用静态方法。如果您调用static native synchronized方法,static native方法或static方法,则会生成此说明。

以下是生成字节码的示例代码:

    public static void main( String[] args ){
            doSomething1();
            System.out.println("Now do 2");
            doSomething2();
            System.out.println("native java");
            doSomethingJava();

            String s = "test";
            synchronized ( s ){
                    int x = 9 + 5;
            }
    }

    public static native void doSomething1();
    public static synchronized native void doSomething2();

    public static synchronized void doSomethingJava(){
            System.out.println("synchronized");
    }

生成的字节码:

Compiled from "test.java"
class test {
  test();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #2                  // Method doSomething1:()V
       3: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
       6: ldc           #4                  // String Now do 2
       8: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      11: invokestatic  #6                  // Method doSomething2:()V
      14: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      17: ldc           #7                  // String native java
      19: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      22: invokestatic  #8                  // Method doSomethingJava:()V
      25: ldc           #9                  // String test
      27: astore_1      
      28: aload_1       
      29: dup           
      30: astore_2      
      31: monitorenter  
      32: bipush        14
      34: istore_3      
      35: aload_2       
      36: monitorexit   
      37: goto          47
      40: astore        4
      42: aload_2       
      43: monitorexit   
      44: aload         4
      46: athrow        
      47: return        
    Exception table:
       from    to  target type
          32    37    40   any
          40    44    40   any

  public static native void doSomething1();

  public static synchronized native void doSomething2();

  public static synchronized void doSomethingJava();
    Code:
       0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #10                 // String synchronized
       5: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return        
}

答案 1 :(得分:2)

嗯,这使得访问该方法是互斥的。如果这是你正确线程安全的想法,那么我确实相信它。

[编辑:]当然没有办法告诉你这个方法是否是线程安全的,只是来自它的签名。实际上,即使该方法的来源可能也不是足够的信息。线程安全是关于同步对资源的访问。如果你的方法没有访问任何资源,那么即使没有'synchronized'关键字,它的线程也是安全的。

如果同步关键字同步资源访问,则会使线程安全,即您的类具有私有字段,并且修改它的每个方法都是同步的。