Java: нужно ли синхронизировать все статические методы?

у меня есть друг, который говорит, что все статические методы должны быть synchronized в контексте веб-приложения Java. Это правда? Я прочитал много других страниц переполнения стека об этом. Я пришел к выводу, что вам нужно синхронизировать, только если у вас есть:

  1. несколько потоков (как в контейнере Sevlet с пулом потоков)
  2. Одиночный Загрузчик Классов
  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);
                    }
                }
            }
        });
    }
}

этот код доказательства?

EDIT: это только какой-то одноразовый код, который я взломал, чтобы доказать это.

5 ответов


нет, не все статические методы должны быть синхронизированы. Насколько я вижу, ваш список в основном полный. Будьте особенно осторожны, когда статический метод либо

  1. доступ к статическому члену, который является изменяемым, или
  2. передается ссылка на объект, который может быть изменен.

Я думаю, само собой разумеется, что 1 (наличие потоков в первую очередь) является предварительным условием, так как без потоков synchronize нет чувство.

Я никогда не слышал 2, поэтому я не знаю точно, является ли это соображением.


нет, это не так, и я уверен, что это будет пагубно. Не каждое приложение должно быть параллельным, и даже в приложениях, которые должны быть параллельными, не каждый фрагмент кода должен быть.

как больше доказательств, посмотрите на источник строки. там много статических методов, но я мог найти только один синхронизированный метод, и этот даже не статический.


статические методы должны почти никогда быть синхронизированы в webapp. Если вы не уверены на 100%, что единственные люди, которые когда-либо будут использовать приложение, - это ваша бухгалтерская команда из 3 человек и готовы покраснеть, если она взлетит по всей компании и внезапно остановится.

создание глобального, блокирующего, общего ресурса-это полный сбой в масштабируемости! Это также вызовет у вас много головных болей и, вероятно, запереть вас в терракоте решение стиля, Если вам нужно кластеризировать сервер приложений.


в веб-приложении (например, одна сборка с использованием сервлета/JSP) вы всегда должны избегать синхронизации метода, поскольку он бросает вызов всей философии доступности mutli-thread. На месте всегда старайтесь разместить единственный необходимый код, к которому нужно обращаться один за другим, внутри синхронизированного блока.


совсем нет. В основном статические методы, с которыми я столкнулся, не изменяют статические переменные и, следовательно, они не требуют синхронизироваться.

для простого понимания,

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

вышеуказанный метод может быть вызван 1000s потоков, и все же он будет потокобезопасным, потому что метод требует только аргумента -строка и это из стека потоков. Это не общие данные между нити.

подумайте об этом, если все статические методы были синхронизированы, веб-приложения должны быть чрезвычайно медленными и вялыми в использовании. Мы будем иметь блокировку уровня класса всякий раз, когда один поток пытается получить доступ к методу.

в API, предоставляемых JDK, есть много статических методов. Если бы все они были синхронизированы, я уверен, что мы не использовали бы JAVA.

в вашем случае, есть статическая переменная(переменная уровня класса), которая модифицируется статический метод. Да, если создано несколько потоков и они собираются получить доступ к статическому методу, существует возможность интерференции потоков. Это не потокобезопасно, как есть общие сведения между ними.

в основном статические методы являются функциями полезности в зависимости от передаваемых им аргументов.

обратите внимание:несинхронизированные статические методы являются потокобезопасными, если они не изменяют статические переменные класса.