我有一位朋友说在Java Web应用程序的上下文中所有静态方法都应该是synchronized
。真的吗?我已经阅读了很多关于此的堆栈溢出页面。我所相信的是,如果你有以下内容,你只需要同步:
基于此,我认为静态成员应该是同步的,而不是静态方法。
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);
}
}
}
});
}
}
此代码是否证明了这一点?
编辑:这只是我破解的一些一次性代码来证明这一点。
答案 0 :(得分:10)
不,并非所有静态方法都需要同步。就我所见,你的清单基本上已经完成。静态方法时要特别小心
我认为不用说1(首先有线程)是一个先决条件,因为没有线程synchronize
没有意义。
我从未听过2,所以我不确定这是否是一个考虑因素。
答案 1 :(得分:4)
不,这不是真的,我相信这会是有害的。并非每个应用程序都需要并发,即使在需要并发的应用程序中,也不是每个代码都必须。
作为更多证据,look at the source of String.那里有很多静态方法,但我只能找到一个同步方法,而且一个方法甚至不是静态方法。
答案 2 :(得分:2)
静态方法几乎应该从不在webapp中同步。除非你100%确定将会使用该应用程序的唯一人员是你的3人会计团队,并且如果它在全公司范围内起飞并且所有的突然研究几乎停止,那么他们愿意变红。
创建全局,阻塞,共享资源是可扩展性的彻底失败!如果您最终需要集群应用程序服务器,这也会让您感到很头疼,并可能将您锁定为Terracotta风格的解决方案。
答案 3 :(得分:1)
在Web应用程序中(比如使用servlet / JSP的一个构建),您应该始终避免使方法同步,因为它挑战了多线程可访问性的整体哲学。在适当的位置,总是尝试在synchronized块中放置唯一需要逐个访问的必要代码。
答案 4 :(得分:1)
完全没有。大多数情况下,我遇到的静态方法不会修改任何静态变量,因此它们不需要同步。
为了便于理解,
//sample static util method to get string in upper case
public static String getName(String name){
return a.toUpperCase();
}
上述方法可以被1000个线程调用,但它将是线程安全的,因为该方法只需要一个参数 - 字符串名称,并且来自线程堆栈。它不是线程之间的共享数据。
考虑一下,如果所有静态方法都是同步的,那么Web应用程序应该非常慢并且难以使用。只要一个线程试图访问该方法,我们就会有类级锁。
JDK提供的API中有很多静态方法。如果所有这些都是同步的,我很确定我们不会使用JAVA。
在您的情况下,静态变量(类级别变量)正由静态方法修改。是的,如果创建了多个线程并且它们将访问静态方法,则可能存在线程干扰。它不是线程安全的,因为它们之间存在共享数据。
大多数情况下,静态方法是实用函数,具体取决于传递给它们的参数。
请注意,如果非同步静态方法不修改静态类变量,则它们是线程安全的。