У меня есть друг, который сказал, что все статические методы должны быть synchronized
в контексте веб-приложения Java. Это правда? Я прочитал много других страниц переполнения стека относительно этого. То, что я пришел к выводу, что вам нужно только для синхронизации, если у вас есть:Java: Необходимо ли синхронизировать все статические методы?
- многопоточности (как в Sevlet контейнер с пула потоков)
- Single ClassLoader
- Общие данные между потоками, будь то это данные сеанса или статические данные данные.
- Общие данные должны быть изменены. Только для чтения данные доступны для совместного использования.
Основываясь на этом, я думаю, что статические элементы должны быть синхронизированы, но не статическими методами.
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: Это только некоторый код, который я взломал, чтобы доказать свою точку зрения.
Написание потокобезопасного кода ** далека ** сложнее, чем пощелкать 'synchronized' в случайных местах. – SLaks
В качестве примечания, ваш 'safeStaticMethod', как было написано, по-прежнему будет безопасным, используя' StringBuffer', поскольку буфер не разделяется между потоками. он локален для этого конкретного вызова метода. – Charlie
Чтобы продумать вышеизложенное: в принципе нет правил «if X then Y», которые универсальны для написания потокобезопасных программ. (Большинство из тех, кого вы слышите, могут в конечном итоге бесполезно уменьшить параллелизм для вашего приложения.) – millimoose