7
votes

One of my java static method is accessed by multiple threads . Do I need to synchronize the method explicitly by synchronized keyword?.

Sometime back I read in a book which states that

static method is implicitly thread safe as the method is not object specific

.

Well known example is , Singleton implementation. In which getInstance() is static and do we need to mark this as synchronized as well?

 public synchronized static Logger getInstance() {
         if( instance == null ){
             instance = new Logger();
         }

         return instance;
     }

Thanks

5
no! static is not a synonym for synchronized!ΦXocę 웃 Пepeúpa ツ
If that static data is mutable it means that every object sees changes. Is that what you want? Perhaps not.duffymo
But , the method will be having only one copy as it is class level variable . Right?JavaUser
Methods don't have copies at all. I strongly suspect you've misremembered the book - or you should quote it verbatim. Static methods should be made thread-safe, typically - but that's not the same thing.Jon Skeet
Static methods are not thread sate just because they are static. If your class has static field, lets say x=1; and you have static method static void increment(){x++} then you can still face problem with race condition. Static just means that method is invoked on class rather than on instance. If you synchronize it it just means you synchronized it on YourClass.class literal rather than this instance.Pshemo

5 Answers

5
votes

static modifier and thread safety are two distinct matters.

You are in a defacto thead-safety case only when you don't have any race condition.
Having no race condition for a method means that :

  • either the access to the method are done by a single thread

  • or by concurrent threads but only for reading access.

These two things have zero relation with the fact that the method be static or not.

For example in this code :

public static Logger getInstance() {
     if( instance == null ){
         instance = new Logger();
     }

     return instance;
}

It is thread safe defacto if the application is mono threaded.
But it is not the case if it is accessed concurrently by threads as the method doesn't make only reading access.
In this case, you need to synchronize the access to the method.


As a side note, the Bill Pugh idiom singleton spares the use of a synchronized method to implement a singleton.
You can indeed implement it by taking advantage of static initialization done by the JVM as the class is loaded :

public class SingletonBillPughWithEagerCreation {

    // executed as soon as the SingletonBillPughWithEagerCreation class is loaded by the classLoader
    private static SingletonBillPughWithEagerCreation instance = new SingletonBillPughWithEagerCreation();

    private SingletonBillPughWithEagerCreation() {
    }

    public static SingletonBillPughWithEagerCreation getInstance() {
       return instance;
    }
}
4
votes

No, it is not.

The sentence you quote means that the static method is not object specific and, because of the local variable is saved in thread environment, it can only be accessed from the local execution of the thread itself. But in a static method you can access to a static field or an object shared by multiple thread, in that case you are not dealing with a local variable, but with something shared among multiple object.

In other word, since the execution is thread safe, the access to a field of an object is shared to all threads that has access to the object. In that case you have a concurrency problem which have to be handled with the synchronized keyword. With synchronized keyword you make a statement accessible from only one thread per time.

class MyObject{
 static MyType mySharedObject; //if you access this in static methos you are not safe until you sync the access

public static void myMethod(){
   int localVar; //that is safely accessed
   mySharedObject.setSomething(pippo); //that is not safe in multi thread environment.

}

}

3
votes

A method can be considered thread-safe if simultaneous calls from multiple threads will not create a situation, where any memory space is written by one thread, and simultaneously written/read by another thread at the same time.

This example shows a function that if called by multiple threads can cause issues:

void doThreadNonsense(int input) {
  this.myValue = input;
  if (this.myValue > 9000) System.out.println("It's over 9000!");
}

Because here a value is first written, then read by multiple threads, and it could happen that Thread A writes a 5, then Thread B writes a 9000, and then Thread A outputs the sentence, because the value is now > 9000, despite the input of 5.

With however just a minor change this function becomes thread-safe:

void doThreadNonsense(int input) {
  this.myValue = input;
  if (input > 9000) System.out.println("It's over 9000!");
}

Now the value is only written by multiple threads, but since writing an int happens atomically on any 32-bit (or higher) machine, myValue is only written by one thread or another, but never by both at the same time. This example shows how closely you need to check what your code is doing to figure out whether or not it is thread-safe.

If you take a static method it can - as above - also be not thread-safe:

static int myValue;
static void doThreadNonsense(int input) {
  myValue = input;
  if (myValue > 9000) System.out.println("It's over 9000!");
}

However in most cases static functions do not write on static variables (this isn't considered clean code by OOP design patterns), and if you don't access anything outside the scope of the method, the code is automatically thread-safe, because all used memory locations are local to the current thread only.

static void doThreadNonsense(int input) {
  if (input> 9000) System.out.println("It's over 9000!");
}

So your book should have said: "Static methods that follow the clean code paradigm tend to be thread-safe."

This is however not at all helpful, and completely misses the point why something is thread-safe and other things are not. Take the following example, that is surprisingly (to some) thread-safe, despite that it violates many of the "clean threading" rules:

static final int[][] matrix = new int[N][M];

static void fillMatrixColumn(final int n) {
  for (int m = 0; m < M; ++m) {
    matrix[n][m] = calculateValue(n, m);
  }
}

public static void main(String[] args)() {
  IntStream.range(0, N)
    .parallel()
    .forEach(this::fillMatrixColumn);
  printMatrix(matrix);
}

No synchronized, no locking, but a lot of happy writing from multiple threads to the same data structure. This is still thread-safe, because at no point two threads are simultaneously writing to/reading from the same memory location.

2
votes

There are some answers explaining why it's not thread safe, but to answer your quote

static method is implicitly thread safe as the method is not object specific

The JVM instruction invokestatic for static methods documents that

If the method is synchronized, the monitor associated with the resolved Class object is entered or reentered as if by execution of a monitorenter instruction (§monitorenter) in the current thread.

Which means that static methods are not inherently thread-safe in a concurrent environment, because there is a difference between synchronized and non-synchronized static methods.

0
votes

Consider the following example. getInstance is called two times, by threads A and B.

line1:public **synchronized** static Logger getInstance() {
line2:    if( instance == null ){
line3:        instance = new Logger();
line4:    }
line5:
line6:    return instance;
line7:}

A possible execution order might be A2, B2, A3, B3 meaning line 2 is executed by thread A, then by thread B and afterwards line 3 is executed by thread A and B. This will result in instance == B.getInstance(), meaning the Logger that was created when thread B called getInstance. Thread A however is using a different logger!