जब मल्टीथ्रेडिंग की अवधारणा लागू की जाती है, तो यह संभव है कि एक थ्रेड द्वारा किए गए परिवर्तन दूसरे थ्रेड को दिखाई न दें। यह इंगित करता है कि प्रत्येक थ्रेड का दृष्टिकोण एक-दूसरे के संबंध में असंगत है। इसे मेमोरी कंसिस्टेंसी त्रुटि के रूप में जाना जाता है।
CPU मुख्य मेमोरी को एक अलग क्रम में एक्सेस कर सकता है, जबकि थ्रेड्स उन्हें अलग क्रम में एक्सेस कर सकते हैं।
यह आमतौर पर तब होता है जब राइट ऑपरेशन किया जा रहा हो, जिससे CPU प्रतीक्षा समय से बचा जाता है।
राइट ऑपरेशन एक परमाणु ऑपरेशन है, जिसका अर्थ है कि जब एक राइट ऑपरेशन किया जा रहा हो तो अन्य थ्रेड्स द्वारा कोई अन्य ऑपरेशन नहीं किया जाएगा।
इसके अलावा, जिस क्रम में राइट ऑपरेशन किया जाता है, वह हर संबद्ध CPU के लिए सुसंगत रूप से बनाए रखा जाएगा, जबकि CPU अन्य CPU के राइट समय को अलग तरीके से समझ सकते हैं। यह घटना मेमोरी असंगति का कारण बन सकती है।
मेमोरी असंगति त्रुटियों से कैसे बचें?
हैपन्स-बिफोर संबंध स्थापित करने की आवश्यकता है ताकि एक थ्रेड द्वारा मेमोरी राइट किया जाए, और यह उसी मेमोरी पर अन्य थ्रेड द्वारा किए गए रीड ऑपरेशन को दिखाई दे।
'start' फंक्शन और 'join' फंक्शन को हैपन्स-बिफोर संबंध माना जाता है। 'start' फंक्शन यह सुनिश्चित करता है कि नव निर्मित थ्रेड दिखाई दे। 'join' फंक्शन यह सुनिश्चित करता है कि दिखाई देने वाला थ्रेड दूसरे थ्रेड से जुड़ा हुआ है।
उदाहरण
import java.io.*;
class SharedClass {
static int m = 2;
void inc() {
for (int j = 0; j < 5; j++) {
m = m + 1;
System.out.println("इन्क्रीमेंट के बाद है " + m);
}
}
void dec() {
for (int j = 0; j < 5; j++) {
m = m - 1;
System.out.println("डिक्रीमेंट के बाद है " + m);
}
}
}
public class Demo {
public static void main(String[] args) {
final SharedClass my_inst = new SharedClass();
Thread my_t_1 = new Thread() {
@Override
public void run() {
my_inst.inc();
}
};
Thread my_t_2 = new Thread() {
@Override
public void run() {
my_inst.dec();
}
};
my_t_1.start();
my_t_2.start();
}
}
आउटपुट
इन्क्रीमेंट के बाद है 3
डिक्रीमेंट के बाद है 2
डिक्रीमेंट के बाद है 2
डिक्रीमेंट के बाद है 1
इन्क्रीमेंट के बाद है 3
डिक्रीमेंट के बाद है 0
इन्क्रीमेंट के बाद है 1
इन्क्रीमेंट के बाद है 1
डिक्रीमेंट के बाद है 0
इन्क्रीमेंट के बाद है 2
व्याख्या: 'SharedClass' नामक एक क्लास एक स्थिर मान परिभाषित करती है, और एक void फंक्शन, जो संख्याओं के एक सेट पर पुनरावृति करता है, और इसे इन्क्रीमेंट करता है और कंसोल पर प्रदर्शित करता है। 'dec' नामक एक अन्य फंक्शन संख्याओं के एक सेट पर पुनरावृति करता है और हर बार डिक्रीमेंट करता है और आउटपुट को कंसोल पर प्रदर्शित करता है। Demo नामक एक क्लास मुख्य फंक्शन रखती है जो क्लास का एक इंस्टेंस बनाता है, और एक नया थ्रेड बनाता है। इस थ्रेड को ओवरराइड किया जाता है, और इस ऑब्जेक्ट इंस्टेंस पर run फंक्शन को कॉल किया जाता है। दूसरे थ्रेड के लिए भी यही किया जाता है। दोनों थ्रेड्स को फिर 'start' फंक्शन के साथ कॉल किया जाता है।
समाधान: सिंक्रोनाइजेशन
synchronized void inc() { ... }
synchronized void dec() { ... }
// या
synchronized(this) {
m = m + 1;
}
सिंक्रोनाइज्ड ब्लॉक/मेथड्स हैपन्स-बिफोर संबंध स्थापित करते हैं, मेमोरी विजिबिलिटी सुनिश्चित करते हैं।