我有一个这样定义的本机方法方法:
public static native int doSomething();
但是,此方法不是线程安全的。所以,我在上面放了一个synchronized
关键字,所以现在看起来像这样:
public static synchronized native int doSomething();
这似乎解决了这个问题,但我不确定它是否真的解决了。这是有效的吗?它实际上是否正确锁定了对该方法的访问?
我有一个这样定义的本机方法方法:
public static native int doSomething();
但是,此方法不是线程安全的。所以,我在上面放了一个synchronized
关键字,所以现在看起来像这样:
public static synchronized native int doSomething();
这似乎解决了这个问题,但我不确定它是否真的解决了。这是有效的吗?它实际上是否正确锁定了对该方法的访问?
在阅读了相关的JLS 部分之后,JLS 中没有任何内容禁止static
和native
出现在方法定义中。根据相关的JVM规范:
方法级同步是隐式执行的,作为方法调用和返回的一部分(第 2.11.8 节)。同步方法在运行时常量池的 method_info 结构(第 4.6 节)中由 ACC_SYNCHRONIZED 标志来区分,该标志由方法调用指令检查。当调用设置了 ACC_SYNCHRONIZED 的方法时,执行线程进入监视器,调用方法本身,然后退出监视器,无论方法调用正常完成还是突然完成。在执行线程拥有监视器期间,没有其他线程可以进入它。如果在调用同步方法期间抛出异常,并且同步方法没有处理异常,则在将异常重新抛出同步方法之前自动退出该方法的监视器。
因此,生成的字节码没有任何指令monitorenter
或monitorexit
指令,就像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
}
好吧,它使访问该方法互斥。如果这是您正确线程安全的想法,那么我相信它是。
[编辑:]当然,仅从其签名无法告诉您该方法是否是线程安全的。事实上,即使是方法的来源也可能没有足够的信息。线程安全是关于同步对资源的访问。如果您的方法不访问任何资源,那么即使没有“同步”关键字,它也是线程安全的。
如果同步资源访问, synchronized 关键字使某些东西成为线程安全的,即您的类有一个私有字段,并且修改它的每个方法都是同步的。