简体   繁体   中英

Java: Do all static methods need to be synchronized?

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.

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.

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.

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.

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.

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM