5

I have a native method method defined like this:

public static native int doSomething();

However, this method is not thread-safe. So, I put a synchronized keyword on it, so it looks like this now:

public static synchronized native int doSomething();

This appears to fix the problem, but I'm not sure if it actually does. Is this valid? Does it actually properly lock access to the method?

rm5248
  • 2,590
  • 3
  • 17
  • 16
  • Are you authoring the native method? Thread safeness depends on more than just synchronized access. This importantly includes what the behavior of the native method is ... is it accessing shared or global data? A thread-hostile method (worst case scenario) cannot be made thread-safe no matter how much external synchronization is used. – scottb May 31 '13 at 01:20

2 Answers2

5

After reading the relevant JLS section, there is nothing in the JLS which prohibits static and native from being in the method definition. According to the relevant JVM spec:

Method-level synchronization is performed implicitly, as part of method invocation and return (§2.11.8). A synchronized method is distinguished in the run-time constant pool's method_info structure (§4.6) by the ACC_SYNCHRONIZED flag, which is checked by the method invocation instructions. When invoking a method for which ACC_SYNCHRONIZED is set, the executing thread enters a monitor, invokes the method itself, and exits the monitor whether the method invocation completes normally or abruptly. During the time the executing thread owns the monitor, no other thread may enter it. If an exception is thrown during invocation of the synchronized method and the synchronized method does not handle the exception, the monitor for the method is automatically exited before the exception is rethrown out of the synchronized method.

Because of this, the bytecode that is generated does not have any monitorenter or monitorexit instructions, as a synchronized block does. The only thing that is generated in this case is invokestatic, in order to invoke the static method. This instruction is generated if you call a static native synchronized method, a static native method, or a static method.

Here's some example code with the generated bytecode:

    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");
    }

Generated bytecode:

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        
}
rm5248
  • 2,590
  • 3
  • 17
  • 16
2

Well, it makes accessing the method mutually exclusive. If that is your idea of properly threadsafe, then I do believe it is.

[Edit:] Of course there is no way of telling you whether the method is threadsafe or not just from its signature. In fact, even the method's source may not be sufficient information. Thread safety is about synchronizing access to resources. If your method does not access any resource, then its threadsafe even without the 'synchronized'-keyword.

The synchronized keyword makes something threadsafe if it synchronizes resource access, i.e. your class has a private field, and every method that modifies it is synchronized.

Janis F
  • 2,637
  • 1
  • 25
  • 36