2013-02-13 5 views
6

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

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

Означает ли этот код смысл?

EDIT: Это только некоторый код, который я взломал, чтобы доказать свою точку зрения.

+8

Написание потокобезопасного кода ** далека ** сложнее, чем пощелкать 'synchronized' в случайных местах. – SLaks

+1

В качестве примечания, ваш 'safeStaticMethod', как было написано, по-прежнему будет безопасным, используя' StringBuffer', поскольку буфер не разделяется между потоками. он локален для этого конкретного вызова метода. – Charlie

+1

Чтобы продумать вышеизложенное: в принципе нет правил «if X then Y», которые универсальны для написания потокобезопасных программ. (Большинство из тех, кого вы слышите, могут в конечном итоге бесполезно уменьшить параллелизм для вашего приложения.) – millimoose

ответ

9

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

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

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

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

4

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

Как больше доказательств, look at the source of String. Есть много статических методов, но я мог найти только один синхронизированный метод, и он даже не статичен.

+2

Поскольку строка не синхронизирована, это потому, что String неизменен - ​​в основном потому, что неизменяемые объекты доступны только для чтения и, следовательно, являются неотъемлемо безопасными (пункт 4 в исходном вопросе). Строка на самом деле является одним из лучших примеров класса, разработанного явно, чтобы избежать использования 'synchronized' и по-прежнему быть в безопасности. – Matt

+2

Да, это правда, он указал на это с точки 4, но вопрос в том, нужно ли ** все ** статические методы синхронизировать, и это пример, показывающий: «Нет, они этого не делают» –

+1

О, действительно. Теперь я понимаю - хороший пример :) – Matt

2

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

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

1

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

1

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

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

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

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

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

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

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

В основном, статические методы - это служебные функции в зависимости от передаваемых им аргументов.

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

Смежные вопросы