Tôi có một người bạn nói rằng tất cả các phương pháp tĩnh phải là synchronized
trong ngữ cảnh của một ứng dụng web Java. Điều đó có đúng không? Tôi đã đọc nhiều trang tràn ngăn xếp khác về vấn đề này. Những gì tôi đã đi đến chỗ tin là bạn chỉ cần để đồng bộ hóa nếu bạn có:Java: Có phải tất cả các phương thức tĩnh cần được đồng bộ hóa không?
- Nhiều Chủ đề (Như trong một Sevlet container với một hồ bơi thread)
- ClassLoader Độc
- chung dữ liệu giữa các chủ đề, cho dù đó là dữ liệu Phiên hoặc dữ liệu thành viên thành viên.
- Dữ liệu được chia sẻ phải có thể thay đổi. Chỉ đọc dữ liệu là ok để chia sẻ.
Dựa trên điều này tôi nghĩ rằng các thành viên tĩnh phải được đồng bộ hóa, nhưng không phải là phương pháp tĩnh.
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);
}
}
}
});
}
}
Mã này có chứng minh được điểm không?
CHỈNH SỬA: Đây chỉ là một số mã ném tôi đã tấn công để chứng minh điểm.
Viết mã an toàn chủ đề ** phức tạp hơn nhiều so với tát 'đồng bộ hóa' ở những vị trí ngẫu nhiên. – SLaks
Như một lưu ý phụ, 'safeStaticMethod' của bạn được viết sẽ vẫn an toàn bằng cách sử dụng một' StringBuffer', vì bộ đệm không được chia sẻ giữa các luồng. nó là cục bộ cho lời gọi phương thức cụ thể đó. – Charlie
Để giải thích ở trên: về cơ bản không có quy tắc "nếu X sau đó Y" có giá trị chung để viết các chương trình an toàn. (Hầu hết những cái bạn nghe có thể kết thúc không cần thiết giảm đồng thời cho ứng dụng của bạn.) – millimoose