简体   繁体   English

Java:是否需要同步所有静态方法?

[英]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. 我有一个朋友说,所有静态方法都应该在Java Web应用程序的上下文中synchronized 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) 多个线程(如在带有线程池的Sevlet容器中)
  2. Single ClassLoader 单个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. 我认为不用说1(首先有线程)是一个先决条件,因为没有线程synchronize是没有意义的。

I've never heard 2, so I don't know for sure if it's a consideration. 我从来没有听过2,所以我不确定这是否是一个考虑因素。

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. 作为更多证据,请查看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. 静态方法几乎应该在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. 除非你100%确定将会使用该应用程序的唯一人员是你的3人会计团队,并且如果它在全公司范围内起飞并且所有的突然研究几乎停止,那么他们愿意变红。

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. 如果您最终需要集群应用程序服务器,这也会让您感到很头疼,并可能将您锁定为Terracotta样式解决方案。

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. 在Web应用程序中(比如使用servlet / JSP的一个构建),您应该始终避免使方法同步,因为它挑战了多线程可访问性的整个原则。 In place, always try to place the only necessary code, which needs to be accessed one by one, inside the synchronized block. 在适当的位置,始终尝试在synchronized块中放置唯一需要逐个访问的必要代码。

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. 上面的方法可以被1000个线程调用,但它将是线程安全的,因为该方法只需要一个参数 - 字符串名称 ,并且来自线程堆栈。 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. 想一想,如果所有静态方法都是同步的,那么Web应用程序应该非常慢并且难以使用。 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. JDK提供的API中有很多静态方法。 If all those were synchronized, am pretty sure we wouldn't be using JAVA. 如果所有这些都是同步的,我很确定我们不会使用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 . 请注意,如果非同步静态方法不修改静态类变量,则它们是线程安全的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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