या धड्यात, आपण java.lang.ThreadLocal<> वर्गासोबत काम करणे आणि मल्टीथ्रेड वातावरणात ते कसे वापरायचे याबद्दल बोलू .

थ्रेडलोकल क्लास व्हेरिएबल्स साठवण्यासाठी वापरला जातो. या वर्गाचे वैशिष्ट्य म्हणजे ते वापरून प्रत्येक थ्रेडसाठी मूल्याची स्वतंत्र स्वतंत्र प्रत ठेवते.

वर्गाच्या ऑपरेशनमध्ये अधिक खोलवर जाऊन, आम्ही एका नकाशाची कल्पना करू शकतो जो थ्रेड्सला मूल्यांमध्ये मॅप करतो, ज्यावरून वर्तमान थ्रेड वापरण्याची आवश्यकता असताना योग्य मूल्य घेते.

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

कन्स्ट्रक्टर कृती
ThreadLocal() Java मध्ये रिक्त व्हेरिएबल तयार करते

पद्धती

पद्धत कृती
मिळवा() सध्याच्या थ्रेडच्या स्थानिक व्हेरिएबलचे मूल्य मिळवते
सेट() सध्याच्या थ्रेडसाठी स्थानिक व्हेरिएबलचे मूल्य सेट करते
काढून टाका() सध्याच्या थ्रेडच्या स्थानिक व्हेरिएबलचे मूल्य काढून टाकते
ThreadLocal.withInitial() अतिरिक्त फॅक्टरी पद्धत जी प्रारंभिक मूल्य सेट करते

मिळवा() आणि सेट करा()

चला एक उदाहरण लिहूया जिथे आपण दोन काउंटर तयार करतो. पहिले, एक सामान्य चल, थ्रेड्सची संख्या मोजण्यासाठी असेल. दुसरे आपण 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());
    }
}

आमच्या वर्गाच्या प्रत्येक धावाने, आम्ही वाढवतोकाउंटरथ्रेडलोकल व्हेरिएबलमधून डेटा मिळविण्यासाठी व्हेरिएबल 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 सह प्रक्रिया पूर्ण झाली

आणि इथे आपण सहजपणे पाहू शकतो की दुसऱ्या थ्रेडमधील ThreadLocal व्हेरिएबल null आहे .

ThreadLocal.withInitial()

ही पद्धत थ्रेड-लोकल व्हेरिएबल तयार करते.

थ्रेडडेमो वर्गाची अंमलबजावणी :


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 च्या अंमलबजावणीच्या थ्रेडच्या संबंधात स्थानिक व्हेरिएबल्सवर एक अमूर्तता प्रदान करते.

थ्रेडलोकल व्हेरिएबल्स सामान्य व्हेरिएबल्सपेक्षा भिन्न असतात कारण प्रत्येक थ्रेडचे स्वतःचे, व्हेरिएबलचे वैयक्तिकरित्या आरंभ केलेले उदाहरण असते, जे get () आणि सेट() पद्धतींद्वारे ऍक्सेस केले जाते.

प्रत्येक थ्रेड, म्हणजे थ्रेड क्लासच्या उदाहरणाशी संबंधित थ्रेडलोकल व्हेरिएबल्सचा नकाशा असतो . नकाशाच्या की थ्रेडलोकल ऑब्जेक्ट्सचे संदर्भ आहेत आणि मूल्ये "अधिग्रहित" थ्रेडलोकल व्हेरिएबल्सचे संदर्भ आहेत.

मल्टीथ्रेडेड ऍप्लिकेशन्समध्ये यादृच्छिक संख्या निर्माण करण्यासाठी यादृच्छिक वर्ग का योग्य नाही?

यादृच्छिक संख्या मिळविण्यासाठी आम्ही Random वर्ग वापरतो. पण मल्टीथ्रेड केलेल्या वातावरणात ते तसेच कार्य करते का? खरं सांगायचं तर, नाही. यादृच्छिक मल्टीथ्रेड वातावरणासाठी योग्य नाही, कारण जेव्हा एकाधिक थ्रेड एकाच वेळी वर्गात प्रवेश करतात, तेव्हा कार्यप्रदर्शन प्रभावित होते.

या समस्येचे निराकरण करण्यासाठी, JDK 7 ने java.util.concurrent.ThreadLocalRandom क्लास मल्टीथ्रेडेड वातावरणात यादृच्छिक संख्या निर्माण करण्यासाठी सादर केला. यात दोन वर्ग आहेत: ThreadLocal आणि Random .

एका थ्रेडद्वारे प्राप्त झालेल्या यादृच्छिक संख्या इतर थ्रेडपेक्षा स्वतंत्र आहेत, परंतु java.util.Random जागतिक स्तरावर यादृच्छिक संख्या प्रदान करते. तसेच, Random च्या विपरीत , ThreadLocalRandom स्पष्ट सीडिंगला समर्थन देत नाही. त्याऐवजी, ते Random कडून मिळालेली setSeed() पद्धत ओव्हरराइड करते , जेणेकरून कॉल केल्यावर ते नेहमी UnsupportedOperationException टाकते.

चला ThreadLocalRandom वर्गाच्या पद्धती पाहू :

पद्धत कृती
ThreadLocalRandom current() सध्याच्या थ्रेडचा ThreadLocalRandom मिळवते.
int पुढील (इंट बिट्स) पुढील छद्म-यादृच्छिक संख्या व्युत्पन्न करते.
दुहेरी नेक्स्ट डबल (कमीतकमी दुप्पट, दुहेरी बाउंड) कमीत कमी (समावेशक) आणि बद्ध (अनन्य) मधील समान वितरणातून एक छद्म यादृच्छिक संख्या मिळवते .
int nextInt(int किमान, int बद्ध) कमीत कमी (समावेशक) आणि बद्ध (अनन्य) मधील समान वितरणातून एक छद्म यादृच्छिक संख्या मिळवते.
लांब पुढचा लांब (लांब n) 0 (समावेशक) आणि निर्दिष्ट मूल्य (अनन्य) मधील एकसमान वितरणातून एक छद्म यादृच्छिक संख्या मिळवते.
लांब पुढचा लांब (किमान लांब, लांब बांधलेला) कमीत कमी (समावेशक) आणि बद्ध (अनन्य) मधील समान वितरणातून एक छद्म यादृच्छिक संख्या मिळवते.
शून्य सेटसीड (लांब बियाणे) UnsupportedOperationException फेकते . हा जनरेटर पेरणीला सपोर्ट करत नाही.

ThreadLocalRandom.current() वापरून यादृच्छिक क्रमांक मिळवणे

ThreadLocalRandom हे ThreadLocal आणि Random वर्गांचे संयोजन आहे. यादृच्छिक वर्गाच्या घटनांमध्ये समवर्ती प्रवेश टाळून ते मल्टीथ्रेडेड वातावरणात चांगले कार्यप्रदर्शन प्राप्त करते.

चला एकापेक्षा जास्त थ्रेड्सचा समावेश असलेले एक उदाहरण अंमलात आणू आणि आमचा अनुप्रयोग ThreadLocalRandom वर्गासोबत करतो ते पाहू:


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
थ्रेड
29 व्युत्पन्न 33

आणि आता आपला RandomNumbers वर्ग बदलू आणि त्यामध्ये Random वापरू:


int result = new Random().nextInt(bound);
वेळ लागला: 5
धागा 20 व्युत्पन्न 48
धागा 19 व्युत्पन्न 57
थ्रेड 18 व्युत्पन्न 90
धागा 22 व्युत्पन्न 43
धागा 24 व्युत्पन्न 7
धागा 23 व्युत्पन्न 63
धागा 15 व्युत्पन्न 2
थ्रेड 16
थ्रेड 19 व्युत्पन्न 19
थ्रेड 19 व्युत्पन्न 2

नोंद घ्या! आमच्या चाचण्यांमध्ये, काहीवेळा परिणाम समान होते आणि काहीवेळा ते वेगळे होते. परंतु जर आपण अधिक थ्रेड्स वापरतो (म्हणा, 100), परिणाम असे दिसेल:

यादृच्छिक — 19-25 ms
ThreadLocalRandom — 17-19 ms

त्यानुसार, आमच्या ऍप्लिकेशनमध्ये जितके जास्त थ्रेड्स, मल्टीथ्रेड वातावरणात रँडम क्लास वापरताना परफॉर्मन्स हिट होईल .

यादृच्छिक आणि ThreadLocalRandom वर्गांमधील फरकांचा सारांश आणि पुनरावृत्ती करण्यासाठी :

यादृच्छिक ThreadLocalRandom
जर भिन्न थ्रेड्स Random ची समान उदाहरणे वापरत असतील तर , संघर्ष होईल आणि कार्यप्रदर्शनास नुकसान होईल. कोणतेही विवाद किंवा समस्या नाहीत, कारण व्युत्पन्न यादृच्छिक संख्या सध्याच्या थ्रेडसाठी स्थानिक आहेत.
प्रारंभिक मूल्य बदलण्यासाठी एक रेखीय एकत्रित सूत्र वापरते. यादृच्छिक क्रमांक जनरेटर अंतर्गत व्युत्पन्न बियाणे वापरून आरंभ केला जातो.
अनुप्रयोगांमध्ये उपयुक्त जेथे प्रत्येक थ्रेड स्वतःच्या यादृच्छिक वस्तूंचा संच वापरतो. अ‍ॅप्लिकेशन्समध्ये उपयुक्त जेथे एकाधिक थ्रेड्स थ्रेड पूलमध्ये समांतर यादृच्छिक संख्या वापरतात.
हा पालक वर्ग आहे. हा बालवर्ग आहे.