Java: нужно ли синхронизировать все статические методы?
у меня есть друг, который говорит, что все статические методы должны быть synchronized
в контексте веб-приложения Java. Это правда? Я прочитал много других страниц переполнения стека об этом. Я пришел к выводу, что вам нужно синхронизировать, только если у вас есть:
- несколько потоков (как в контейнере Sevlet с пулом потоков)
- Одиночный Загрузчик Классов
- общие данные между потоками, будь то данные сеанса или статические данные.
- общие данные должны быть изменяемы. Только для чтения данных можно поделиться.
основываясь на этом, я думаю, что статические члены должны быть синхронизированы, но не статические методы.
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 (наличие потоков в первую очередь) является предварительным условием, так как без потоков 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.
в вашем случае, есть статическая переменная(переменная уровня класса), которая модифицируется статический метод. Да, если создано несколько потоков и они собираются получить доступ к статическому методу, существует возможность интерференции потоков. Это не потокобезопасно, как есть общие сведения между ними.
в основном статические методы являются функциями полезности в зависимости от передаваемых им аргументов.
обратите внимание:несинхронизированные статические методы являются потокобезопасными, если они не изменяют статические переменные класса.