मेरे पास एक दोस्त है जिसने कहा है कि जावा वेब एप्लिकेशन के संदर्भ में सभी स्थैतिक विधियां synchronized
होनी चाहिए। क्या यह सच है? मैंने इसके बारे में कई अन्य स्टैक ओवरफ्लो पेज पढ़े हैं।जावा: क्या सभी स्थिर तरीकों को सिंक्रनाइज़ करने की आवश्यकता है?
- एकाधिक धागे (एक Sevlet कंटेनर में के रूप में एक धागा पूल के साथ)
- धागे के बीच साझा किया गया डेटा, चाहे
- एकल 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);
}
}
}
});
}
}
क्या यह कोड बिंदु साबित करता है?
संपादित करें: यह केवल कुछ फेंकने वाला कोड है जो मैंने बिंदु साबित करने के लिए हैक किया है।
लेखन थ्रेड-सुरक्षित कोड ** यादृच्छिक स्थानों में 'सिंक्रनाइज़' को थप्पड़ मारने से ** अधिक जटिल है। – SLaks
एक साइड नोट के रूप में, लिखित के रूप में आपका 'सुरक्षित स्टेटिक विधि' अभी भी 'स्ट्रिंगबफर' का उपयोग करके सुरक्षित होगा, क्योंकि बफर थ्रेड के बीच साझा नहीं किया जाता है। यह उस विशेष विधि के आमंत्रण के लिए स्थानीय है। – Charlie
उपर्युक्त पर विस्तृत करने के लिए: मूल रूप से कोई नहीं है "यदि एक्स तो वाई" नियम जो थ्रेडसेफ प्रोग्राम लिखने के लिए सार्वभौमिक रूप से मान्य हैं। (जिन लोगों में आप सुनते हैं उनमें से अधिकांश आपके ऐप के लिए अनिवार्य रूप से कम करने के लिए समाप्त हो सकते हैं।) – millimoose