我有一个像这样定义的本机方法:
public static native int doSomething();
但是,此方法不是线程安全的。所以,我在其上放了一个synchronized
关键字,所以它现在看起来像这样:
public static synchronized native int doSomething();
这似乎可以解决问题,但我不确定它是否确实存在。这有效吗?它是否实际上正确锁定了对方法的访问权限?
答案 0 :(得分:5)
在阅读相关的JLS section后,JLS中没有任何内容禁止static
和native
进入方法定义。根据{{3}}
方法级同步是隐式执行的,作为方法调用和返回的一部分(第2.18.8节)。同步方法在运行时常量池的method_info结构(第4.6节)中通过ACC_SYNCHRONIZED标志区分,该标志由方法调用指令检查。当调用设置了ACC_SYNCHRONIZED的方法时,执行线程进入监视器,调用方法本身,并退出监视器,无论方法调用是正常还是突然完成。在执行线程拥有监视器期间,没有其他线程可以输入它。如果在调用synchronized方法期间抛出异常并且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
}
答案 1 :(得分:2)
嗯,这使得访问该方法是互斥的。如果这是你正确线程安全的想法,那么我确实相信它。
[编辑:]当然没有办法告诉你这个方法是否是线程安全的,只是来自它的签名。实际上,即使该方法的来源可能也不是足够的信息。线程安全是关于同步对资源的访问。如果你的方法没有访问任何资源,那么即使没有'synchronized'关键字,它的线程也是安全的。
如果同步关键字同步资源访问,则会使线程安全,即您的类具有私有字段,并且修改它的每个方法都是同步的。