इस पाठ में, हम आम तौर पर java.lang.ThreadLocal<> क्लास के साथ काम करने और मल्टीथ्रेडेड वातावरण में इसका उपयोग करने के बारे में बात करेंगे।

थ्रेडलोकल क्लास का उपयोग वेरिएबल्स को स्टोर करने के लिए किया जाता है। इस वर्ग की एक विशिष्ट विशेषता यह है कि इसका उपयोग करने वाले प्रत्येक थ्रेड के लिए मूल्य की एक अलग स्वतंत्र प्रति रखता है।

वर्ग के संचालन में गहराई से जाने पर, हम एक ऐसे मानचित्र की कल्पना कर सकते हैं जो थ्रेड्स को मानों से मैप करता है, जिससे वर्तमान थ्रेड उचित मान लेता है जब उसे इसका उपयोग करने की आवश्यकता होती है।

थ्रेडलोकल क्लास कंस्ट्रक्टर

निर्माता कार्य
थ्रेडलोकल () जावा में एक खाली चर बनाता है

तरीकों

तरीका कार्य
पाना() वर्तमान थ्रेड के स्थानीय चर का मान लौटाता है
तय करना() वर्तमान थ्रेड के लिए स्थानीय चर का मान सेट करता है
निकालना() वर्तमान थ्रेड के स्थानीय चर के मान को हटाता है
थ्रेडलोकल.विथइनिशियल () अतिरिक्त फ़ैक्टरी विधि जो प्रारंभिक मान सेट करती है

तैयार हो जाओ()

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


class ThreadDemo implements Runnable {

    int counter;
    ThreadLocal<Integer> threadLocalCounter = new ThreadLocal<>();

    public void run() {
        counter++;

        if(threadLocalCounter.get() != null) {
            threadLocalCounter.set(threadLocalCounter.get() + 1);
        } else {
            threadLocalCounter.set(0);
        }
        printCounters();
    }

    public void printCounters(){
        System.out.println("Counter: " + counter);
        System.out.println("threadLocalCounter: " + threadLocalCounter.get());
    }
}

हमारी कक्षा के प्रत्येक रन के साथ, हम वृद्धि करते हैंविरोध करनावेरिएबल थ्रेडलोकल वैरिएबल से डेटा प्राप्त करने के लिए गेट () विधि को कॉल करें। यदि नए थ्रेड में कोई डेटा नहीं है, तो हम इसे 0 पर सेट कर देंगे। यदि डेटा है, तो हम इसे एक से बढ़ा देंगे। और चलिए हमारी मुख्य विधि लिखते हैं:


public static void main(String[] args) {
    ThreadDemo threadDemo = new ThreadDemo();

    Thread t1 = new Thread(threadDemo);
    Thread t2 = new Thread(threadDemo);
    Thread t3 = new Thread(threadDemo);

    t1.start();
    t2.start();
    t3.start();

}

अपनी कक्षा को चलाते हुए, हम देखते हैं कि थ्रेडलोकल वैरिएबल वही रहता है, भले ही उस तक पहुँचने वाले थ्रेड की परवाह किए बिना, लेकिन थ्रेड्स की संख्या बढ़ जाती है।

काउंटर: 1
काउंटर: 2
काउंटर: 3
थ्रेडलोकलकाउंटर: 0
थ्रेडलोकलकाउंटर: 0
थ्रेडलोकलकाउंटर: 0

निकास कोड के साथ प्रक्रिया समाप्त 0

निकालना()

यह समझने के लिए कि रिमूव मेथड कैसे काम करता है, हम थ्रेडडेमो क्लास में कोड को थोड़ा बदल देंगे :


if(threadLocalCounter.get() != null) {
      threadLocalCounter.set(threadLocalCounter.get() + 1);
  } else {
      if (counter % 2 == 0) {
          threadLocalCounter.remove();
      } else {
          threadLocalCounter.set(0);
      }
  }

इस कोड में, यदि थ्रेड काउंटर एक सम संख्या है, तो हम अपने थ्रेडलोकल चर पर निकालें () विधि को कॉल करेंगे। परिणाम:

काउंटर: 3
थ्रेडलोकलकाउंटर: 0
काउंटर: 2
थ्रेडलोकलकाउंटर: शून्य
काउंटर: 1
थ्रेडलोकलकाउंटर: 0

निकास कोड के साथ प्रक्रिया समाप्त 0

और यहाँ हम आसानी से देखते हैं कि दूसरे थ्रेड में थ्रेडलोकल वैरिएबल शून्य है ।

थ्रेडलोकल.विथइनिशियल ()

यह विधि थ्रेड-लोकल वैरिएबल बनाती है।

थ्रेडडेमो वर्ग का कार्यान्वयन :


class ThreadDemo implements Runnable {

    int counter;
    ThreadLocal<Integer> threadLocalCounter = ThreadLocal.withInitial(() -> 1);

    public void run() {
        counter++;
        printCounters();
    }

    public void printCounters(){
        System.out.println("Counter: " + counter);
        System.out.println("threadLocalCounter: " + threadLocalCounter.get());
    }
}

और हम अपने कोड का परिणाम देख सकते हैं:

काउंटर: 1
काउंटर: 2
काउंटर: 3
थ्रेडलोकलकाउंटर: 1
थ्रेडलोकलकाउंटर: 1
थ्रेडलोकलकाउंटर: 1

एग्जिट कोड 0 के साथ प्रक्रिया समाप्त

हमें ऐसे चरों का उपयोग क्यों करना चाहिए?

थ्रेडलोकल निष्पादन के धागे के संबंध में स्थानीय चर पर एक अमूर्तता प्रदान करता है java.lang.Thread

थ्रेडलोकल चर सामान्य से भिन्न होते हैं जिसमें प्रत्येक थ्रेड का अपना, चर का व्यक्तिगत रूप से आरंभिक उदाहरण होता है, जिसे गेट () और सेट () विधियों के माध्यम से एक्सेस किया जाता है।

प्रत्येक थ्रेड, यानी थ्रेड क्लास का उदाहरण , इसके साथ जुड़े थ्रेडलोकल चर का एक नक्शा है । मानचित्र की कुंजी थ्रेडलोकल ऑब्जेक्ट्स के संदर्भ हैं, और मान "अधिग्रहीत" थ्रेडलोकल चर के संदर्भ हैं।

बहुप्रचारित अनुप्रयोगों में यादृच्छिक संख्या उत्पन्न करने के लिए यादृच्छिक वर्ग उपयुक्त क्यों नहीं है?

हम यादृच्छिक संख्या प्राप्त करने के लिए यादृच्छिक वर्ग का उपयोग करते हैं। लेकिन क्या यह बहुप्रचारित वातावरण में भी काम करता है? वास्तव में नही। रैंडम मल्टीथ्रेडेड वातावरण के लिए उपयुक्त नहीं है, क्योंकि जब एक ही समय में कई थ्रेड्स एक क्लास तक पहुँचते हैं, तो प्रदर्शन प्रभावित होता है।

इस समस्या को हल करने के लिए, JDK 7 ने बहुप्रचारित वातावरण में यादृच्छिक संख्या उत्पन्न करने के लिए java.util.concurrent.ThreadLocalRandom वर्ग की शुरुआत की। इसमें दो वर्ग होते हैं: थ्रेडलोकल और रैंडम

एक धागे द्वारा प्राप्त यादृच्छिक संख्या अन्य धागे से स्वतंत्र होती है, लेकिन java.util.Random विश्व स्तर पर यादृच्छिक संख्या प्रदान करता है। इसके अलावा, रैंडम के विपरीत , थ्रेडलोकल रैंडम स्पष्ट सीडिंग का समर्थन नहीं करता है। इसके बजाय, यह रैंडम से विरासत में मिली setSeed() विधि को ओवरराइड करता है , ताकि कॉल करने पर यह हमेशा एक UnsupportedOperationException फेंके।

आइए थ्रेडलोकरैंडम वर्ग के तरीकों को देखें:

तरीका कार्य
थ्रेडलोकल रैंडम करंट () वर्तमान थ्रेड का थ्रेडलोकल रैंडम लौटाता है।
इंट नेक्स्ट (इंट बिट्स) अगली छद्म-यादृच्छिक संख्या उत्पन्न करता है।
डबल नेक्स्ट डबल (कम से कम डबल, डबल बाउंड) कम से कम (सम्मिलित) और बाउंड (अनन्य) के बीच समान वितरण से छद्म आयामी संख्या लौटाता है ।
int nextInt (int कम से कम, int बाउंड) कम से कम (सम्मिलित) और बाउंड (अनन्य) के बीच समान वितरण से छद्म आयामी संख्या लौटाता है।
लंबे समय तक (लंबे समय तक) 0 (सम्मिलित) और निर्दिष्ट मान (अनन्य) के बीच समान वितरण से छद्म यादृच्छिक संख्या देता है।
लांग नेक्स्टलॉन्ग (लंबे समय तक, लंबी सीमा) कम से कम (सम्मिलित) और बाउंड (अनन्य) के बीच समान वितरण से छद्म आयामी संख्या लौटाता है।
शून्य सेटसीड (लंबा बीज) असमर्थितऑपरेशन अपवाद फेंकता है । यह जनरेटर बोने का समर्थन नहीं करता है।

थ्रेडलोकलरैंडम.करेंट () का उपयोग करके यादृच्छिक संख्या प्राप्त करना

थ्रेडलोकलरैंडम थ्रेडलोकल और रैंडम क्लासका संयोजन हैयह रैंडम वर्गके उदाहरणों के लिए किसी भी समवर्ती पहुंच से बचकर बहुप्रचारित वातावरण में बेहतर प्रदर्शन प्राप्त करता है।

आइए कई थ्रेड्स से जुड़े एक उदाहरण को लागू करें और देखें कि हमारा एप्लिकेशन थ्रेडलोकल रैंडम क्लास के साथ क्या करता है:


import java.util.concurrent.ThreadLocalRandom;

class RandomNumbers extends Thread {

    public void run() {
        try {
            int bound = 100;
            int result = ThreadLocalRandom.current().nextInt(bound);
            System.out.println("Thread " + Thread.currentThread().getId() + " generated " + result);
        }
        catch (Exception e) {
            System.out.println("Exception");
        }
    }

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();

				for (int i = 0; i < 10; i++) {
            RandomNumbers randomNumbers = new RandomNumbers();
            randomNumbers.start();
        }

        long endTime = System.currentTimeMillis();

        System.out.println("Time taken: " + (endTime - startTime));
    }
}

हमारे कार्यक्रम का परिणाम:

लिया गया समय: 1
थ्रेड 17 उत्पन्न 13
थ्रेड 18 उत्पन्न 41
थ्रेड 16 उत्पन्न 99
थ्रेड 19 उत्पन्न 25
थ्रेड 23 उत्पन्न 33
थ्रेड 24 उत्पन्न 21
थ्रेड 15 उत्पन्न 15
थ्रेड 21 उत्पन्न 28
थ्रेड 22 उत्पन्न 97
थ्रेड 20 उत्पन्न 33

और अब हम अपने RandomNumbers वर्ग को बदलते हैं और इसमें रैंडम का उपयोग करते हैं:


int result = new Random().nextInt(bound);
लिया गया समय: 5
थ्रेड 20 उत्पन्न 48
थ्रेड 19 उत्पन्न 57
थ्रेड 18 उत्पन्न 90
थ्रेड 22 उत्पन्न 43 थ्रेड
24 उत्पन्न 7
थ्रेड 23 उत्पन्न 63
थ्रेड 15 उत्पन्न 2
थ्रेड 16 उत्पन्न 40
थ्रेड 17 उत्पन्न 29
थ्रेड 21 उत्पन्न 12

नोट करें! हमारे परीक्षणों में, कभी-कभी परिणाम समान होते थे और कभी-कभी वे भिन्न होते थे। लेकिन अगर हम अधिक थ्रेड्स का उपयोग करते हैं (कहते हैं, 100), परिणाम इस तरह दिखेगा:

रैंडम - 19-25 एमएस
थ्रेडलोकल रैंडम - 17-19 एमएस

तदनुसार, हमारे आवेदन में जितने अधिक थ्रेड्स हैं, मल्टीथ्रेडेड वातावरण में रैंडम क्लास का उपयोग करते समय प्रदर्शन उतना ही अधिक प्रभावित होता है।

रैंडम और थ्रेडलोकल रैंडम क्लासेस के बीच के अंतरों को समेटने और दोहराने के लिए :

अनियमित थ्रेडलोकलरैंडम
यदि अलग-अलग थ्रेड रैंडम के समान उदाहरण का उपयोग करते हैं , तो विरोध होगा और प्रदर्शन प्रभावित होगा। कोई विरोध या समस्या नहीं है, क्योंकि उत्पन्न यादृच्छिक संख्याएँ वर्तमान थ्रेड के लिए स्थानीय हैं।
प्रारंभिक मान को बदलने के लिए रैखिक सर्वांगसम सूत्र का उपयोग करता है। यादृच्छिक संख्या जनरेटर को आंतरिक रूप से उत्पन्न बीज का उपयोग करके प्रारंभ किया जाता है।
उन अनुप्रयोगों में उपयोगी जहां प्रत्येक थ्रेड रैंडम ऑब्जेक्ट्स के अपने सेट का उपयोग करता है । उन अनुप्रयोगों में उपयोगी जहां कई थ्रेड थ्रेड पूल में समानांतर में यादृच्छिक संख्या का उपयोग करते हैं।
यह एक अभिभावक वर्ग है। यह एक बाल वर्ग है।