繁体   English   中英

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

[英]Java: Do all static methods need to be synchronized?

我有一个朋友说,所有静态方法都应该在Java Web应用程序的上下文中synchronized 真的吗? 我已经阅读了很多关于此的堆栈溢出页面。 我所相信的是,如果你有以下情况,你只需要同步:

  1. 多个线程(如在带有线程池的Sevlet容器中)
  2. 单个ClassLoader
  3. 线程之间的共享数据,无论是会话数据还是静态成员数据。
  4. 共享数据必须是可变的。 只读数据可以共享。

基于此,我认为静态成员应该是同步的,而不是静态方法。

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

这段代码证明了这一点吗?

编辑:这只是我破解的一些一次性代码来证明这一点。

不,并非所有静态方法都需要同步。 就我所见,你的清单基本上已经完成。 静态方法时要特别小心

  1. 访问一个可变的静态成员,或
  2. 获取传递对可修改对象的引用。

我认为不用说1(首先有线程)是一个先决条件,因为没有线程synchronize是没有意义的。

我从来没有听过2,所以我不确定这是否是一个考虑因素。

不,这不是真的,我相信这将是有害的。 并非每个应用程序都需要并发,即使在需要并发的应用程序中,也不是每个代码都必须。

作为更多证据,请查看String的来源。 那里有很多静态方法,但我只能找到一个同步方法,而且那个方法甚至不是静态的。

静态方法几乎应该在webapp中同步。 除非你100%确定将会使用该应用程序的唯一人员是你的3人会计团队,并且如果它在全公司范围内起飞并且所有的突然研究几乎停止,那么他们愿意变红。

创建全局,阻塞,共享资源是可扩展性的完全失败! 如果您最终需要集群应用程序服务器,这也会让您感到很头疼,并可能将您锁定为Terracotta样式解决方案。

在Web应用程序中(比如使用servlet / JSP的一个构建),您应该始终避免使方法同步,因为它挑战了多线程可访问性的整个原则。 在适当的位置,始终尝试在synchronized块中放置唯一需要逐个访问的必要代码。

一点也不。 大多数情况下,我遇到的静态方法不会修改任何静态变量,因此它们不需要同步

为了简单理解,

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

上面的方法可以被1000个线程调用,但它将是线程安全的,因为该方法只需要一个参数 - 字符串名称 ,并且来自线程堆栈。 它不是线程之间的共享数据。

想一想,如果所有静态方法都是同步的,那么Web应用程序应该非常慢并且难以使用。 只要一个线程试图访问该方法,我们就会有类级锁。

JDK提供的API中有很多静态方法。 如果所有这些都是同步的,我很确定我们不会使用JAVA。

在您的情况下, 静态变量 (类级变量)由静态方法修改。 是的,如果创建了多个线程并且它们将访问静态方法,则可能存在线程干扰。 它不是线程安全的,因为它们之间存在共享数据

大多数情况下,静态方法是实用函数,具体取决于传递给它们的参数。

请注意,如果非同步静态方法不修改静态类变量,则它们是线程安全的

暂无
暂无

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

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