Java: Do all static methods need to be synchronized?
Asked Answered
B

5

8

I have a friend who said that all static methods should be synchronized in the context of a Java web application. Is that true? I have read many other stack overflow pages regarding this. What I have come to believe is that you only need to synchronize if you have:

  1. Multiple Threads (As in a Sevlet Container with a thread pool)
  2. Single ClassLoader
  3. Shared data between threads, whether it is Session data or static member data.
  4. Shared data must be mutable. Read only data is ok to share.

Based on this I think that static members should be synchronized, but not static methods.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadTest {

    static String staticString = "";

    // This static method is safe b/c it only uses local data.
    // It does not use any shared mutable data.
    // It even uses a string builder.
    static String safeStaticMethod(String in) {
        // This also proves that StringBuilder is safe
        // When used locally by a thread.
        StringBuilder sb = new StringBuilder();
        sb.append("Hello: ");
        sb.append(in);
        return sb.toString();
    }

    // This static method is not safe b/c it updates and reads
    // shared mutable data among threads.
    // Adding synchronized will make this safe.
    static String unsafeStaticMethod(String in) {
        staticString = in;
        StringBuffer sb = new StringBuffer();
        sb.append("Hello: ");
        sb.append(staticString);
        return sb.toString();
    }

    public static void main(String[] args) {
        ThreadTest test = new ThreadTest();
        test.staticMethodWithLocalData();
        test.staticMethodWithStaticData();
    }

    public void staticMethodWithLocalData() {

        ExecutorService executor = Executors.newFixedThreadPool(2);
        final int iterations = 100000;

        executor.submit(new Runnable() {

            @Override
            public void run() {
                for (int index = 0; index < iterations; ++index) {
                    if (!safeStaticMethod("Thread1").equals("Hello: Thread1")) {
                        System.out.println("safeStaticMethod at " + index);
                    }
                }
            }
        });

        executor.submit(new Runnable() {

            @Override
            public void run() {
                for (int index = 0; index < iterations; ++index) {
                    if (!safeStaticMethod("Thread2").equals("Hello: Thread2")) {
                        System.out.println("safeStaticMethod at " + index);
                    }
                }
            }
        });
    }

    public void staticMethodWithStaticData() {

        ExecutorService executor = Executors.newFixedThreadPool(2);
        final int iterations = 100000;

        executor.submit(new Runnable() {

            @Override
            public void run() {
                for (int index = 0; index < iterations; ++index) {
                    if (!unsafeStaticMethod("Thread1").equals("Hello: Thread1")) {
                        System.out.println("unsafeStaticMethod at " + index);
                    }
                }
            }
        });

        executor.submit(new Runnable() {

            @Override
            public void run() {
                for (int index = 0; index < iterations; ++index) {
                    if (!unsafeStaticMethod("Thread2").equals("Hello: Thread2")) {
                        System.out.println("unsafeStaticMethod at " + index);
                    }
                }
            }
        });
    }
}

Does this code prove the point?

EDIT: This is only some throwaway code I hacked up to prove the point.

Bennir answered 13/2, 2013 at 20:30 Comment(6)
Writing thread-safe code is far more complicated than slapping synchronized in random places.Prepuce
As a side note, your safeStaticMethod as written would still be safe using a StringBuffer, as the buffer is not shared between threads. it is local to that particular method invocation.Anorthite
To elaborate on the above: there are basically no "if X then Y" rules that are universally valid for writing threadsafe programs. (Most of the ones you hear can end up needlessly reducing concurrency for your app.)Grata
See also: stackoverflow.com/questions/5173399Tomy
For example, serialising accesses to random "atoms" (field values) of shared data with synchronized may be insufficient - it may still be incorrect if two related fields are accessed in the wrong order or if a single change should affect both of them consistently. (Recall the classical example of transferring money between bank accounts.) There's also different ways of sharing data in a thread-safe way that may be more appropriate. (Like retrieving consistent read-only snapshots instead of accessing it directly, or using lock-free iterators that survive concurrent modification.)Grata
It's a code smell to have a non-final static variable. Do you have any details on why it cannot be an instance variable?Masteratarms
C
12

No, not all static methods need to be synchronized. Your list is basically complete as far as I can see. Be particularly careful when the static method either

  1. accesses a static member that is mutable, or
  2. gets passed a reference to an object that can be modified.

I think it goes without saying that 1 (having threads in the first place) is a precondition, since without threads synchronize makes no sense.

I've never heard 2, so I don't know for sure if it's a consideration.

Cavorilievo answered 13/2, 2013 at 20:32 Comment(0)
F
4

No that's not true and I'm sure it would be detrimental. Not every application needs to be concurrent, and even in applications that do need to be concurrent, not every piece of code has to be.

As more evidence, look at the source of String. There are many static methods in there, but I could only find one synchronized method, and that one isn't even static.

Flog answered 13/2, 2013 at 20:34 Comment(3)
As far as String not being synchronized, it's because String is immutable - largely because immutable objects are read-only and therefore inherently safe (point 4 in the original question). String is actually one of the best examples of a class designed explicitly to avoid the use of synchronized and still be safe.Blowbyblow
Yes that's true, he pointed that out with point 4, but the question is about if all static methods need to be synchronized and this is an example showing, "no, they do not"Flog
+1 for 'detrimental'. It seems to me that locking a class to provide exclusive access could slow down your application if the method is used a lot.Bennir
M
2

Static methods should almost never be synchronized in a webapp. Unless you are 100% sure that the only people who will ever use the application are your 3 person accounting team, and willing to be red in the face if it takes off company-wide and all of the sudden grinds to a near halt.

Creating a global, blocking, shared resource is a total failure in scalability! It's also going to cause you lots of headaches and likely lock you into a Terracotta style solution if you end up needing to cluster the application server.

Mongolic answered 13/2, 2013 at 20:53 Comment(0)
G
1

In a web application(like one build using the servlet/JSP), you should always avoid making a method as synchronized as it challenges the whole philosophy of mutli-thread accessibility. In place, always try to place the only necessary code, which needs to be accessed one by one, inside the synchronized block.

Gunthar answered 14/5, 2014 at 0:56 Comment(0)
I
1

Not at all. Mostly, the static methods that I have come across do not modify any static variables and hence they do not require to be synchronized.

For simple understanding,

    //sample static util method to get string in upper case    
    public static String getName(String name){
        return a.toUpperCase();
    }

The above method can be called by 1000s of threads and yet it is going to be thread-safe because the method only requires an argument- String name and that is from the Thread Stack. It is not shared data between threads.

Think about it, if all the static methods were synchonized, the web-applications shall be extremely slow and lethargic to use. We shall have class-level lock whenever a single thread tries to access the method.

There are a lot of static methods in the APIs provided by JDK. If all those were synchronized, am pretty sure we wouldn't be using JAVA.

In your case, there is a static variable(class level variable) that is being modified by the static method. Yes, if multiple threads are created and they are going to access the static method, there is a possibility of Thread Interference. It is not thread-safe as there is shared data between them.

Mostly, the static methods are utility functions depending on the arguments being passed to them.

Please note that non-synchronized static methods are thread safe if they don't modify static class variables.

Infralapsarian answered 1/2, 2017 at 9:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.