"हैलो, अमीगो! आपको याद है कि ऐली ने आपको उन समस्याओं के बारे में बताया था जो तब उत्पन्न होती हैं जब कई थ्रेड्स एक साथ एक साझा संसाधन तक पहुँचने का प्रयास करते हैं, हाँ?"

"हाँ।"

"बात यह है, बस इतना ही नहीं है। एक और छोटी सी समस्या है।"

जैसा कि आप जानते हैं, एक कंप्यूटर में मेमोरी होती है जहाँ डेटा और कमांड (कोड) संग्रहीत होते हैं, साथ ही एक प्रोसेसर होता है जो इन कमांड को निष्पादित करता है और डेटा के साथ काम करता है। प्रोसेसर मेमोरी से डेटा पढ़ता है, इसे बदलता है और इसे वापस मेमोरी में लिखता है। संगणनाओं को गति देने के लिए, प्रोसेसर की अपनी अंतर्निहित "तेज़" मेमोरी होती है: कैश।

सबसे अधिक उपयोग किए जाने वाले वेरिएबल्स और मेमोरी के क्षेत्रों को अपने कैश में कॉपी करके प्रोसेसर तेजी से चलता है। फिर यह इस तेज मेमोरी में सारे बदलाव कर देता है। और फिर यह डेटा को वापस «धीमी» मेमोरी में कॉपी करता है। इस सब के दौरान, धीमी मेमोरी में पुराने (अपरिवर्तित!) चर होते हैं।

यहीं से समस्या उत्पन्न होती है। एक धागा एक चर को बदलता है , जैसे कि ऊपर दिए गए उदाहरण में isCancel या isInterrupted है, लेकिन दूसरा धागा «इस परिवर्तन को नहीं देखता है , क्योंकि यह तेज मेमोरी में हुआ है। यह इस तथ्य का परिणाम है कि थ्रेड्स की एक दूसरे के कैश तक पहुंच नहीं है। (एक प्रोसेसर में अक्सर कई स्वतंत्र कोर होते हैं और थ्रेड भौतिक रूप से विभिन्न कोर पर चल सकते हैं।)

आइए कल का उदाहरण याद करें:

कोड विवरण
class Clock implements Runnable
{
private boolean isCancel = false;

public void cancel()
{
this.isCancel = true;
}

public void run()
{
while (!this.isCancel)
{
Thread.sleep(1000);
System.out.println("Tick");
}
}
}
धागा «नहीं जानता» कि अन्य धागे मौजूद हैं।

रन विधि में, पहली बार उपयोग किए जाने पर isCancel चर को चाइल्ड थ्रेड के कैश में डाल दिया जाता है। यह ऑपरेशन निम्न कोड के बराबर है:

public void run()
{
boolean isCancelCached = this.isCancel;
while (!isCancelCached)
{
Thread.sleep(1000);
System.out.println("Tick");
}
}

रद्द करने की विधि को किसी अन्य थ्रेड से कॉल करने से isCancel का मान सामान्य (धीमी) मेमोरी में बदल जाएगा, लेकिन अन्य थ्रेड्स के कैश में नहीं।

public static void main(String[] args)
{
Clock clock = new Clock();
Thread clockThread = new Thread(clock);
clockThread.start();

Thread.sleep(10000);
clock.cancel();
}

"वाह! और क्या वे इसके लिए भी एक सुंदर समाधान लेकर आए, जैसे कि  सिंक्रोनाइज़्ड ?"

"आप विश्वास नहीं करेंगे!"

पहला विचार कैशे को निष्क्रिय करने का था, लेकिन इससे प्रोग्राम कई गुना धीमे चलते हैं। फिर एक अलग उपाय निकला।

वाष्पशील कीवर्ड का जन्म हुआ। हम इस कीवर्ड को वैरिएबल डिक्लेरेशन से पहले यह इंगित करने के लिए रखते हैं कि इसका मान कैश में नहीं डाला जाना चाहिए। अधिक सटीक रूप से, ऐसा नहीं था कि इसे कैश में नहीं डाला जा सकता था, यह बस इतना था कि इसे हमेशा सामान्य (धीमी) मेमोरी से पढ़ा और लिखा जाना था।

यहां हमारे समाधान को ठीक करने का तरीका बताया गया है ताकि सब कुछ ठीक रहे:

कोड विवरण
class Clock implements Runnable
{
private volatile boolean isCancel = false;

public void cancel()
{
this.isCancel = true;
}

public void run()
{
while (!this.isCancel)
{
Thread.sleep(1000);
System.out.println("Tick");
}
}
}
वाष्पशील संशोधक एक चर को हमेशा सभी थ्रेड्स द्वारा साझा की जाने वाली सामान्य मेमोरी से पढ़ने और लिखने का कारण बनता है।
public static void main(String[] args)
{
Clock clock = new Clock();
Thread clockThread = new Thread(clock);
clockThread.start();

Thread.sleep(10000);
clock.cancel();
}

"इतना ही?"

"बस इतना ही। सरल और सुंदर।"