இந்தப் பாடத்தில், java.lang.ThreadLocal<> வகுப்பில் பணிபுரிவது பற்றியும், மல்டித்ரெட் சூழலில் அதை எவ்வாறு பயன்படுத்துவது என்பது பற்றியும் பொதுவாகப் பேசுவோம் .

மாறிகளை சேமிக்க ThreadLocal வகுப்பு பயன்படுத்தப்படுகிறது. இந்த வகுப்பின் ஒரு தனித்துவமான அம்சம் என்னவென்றால், அதைப் பயன்படுத்தும் ஒவ்வொரு நூலுக்கும் ஒரு மதிப்பின் தனித் தனியான நகலை வைத்திருப்பது.

வகுப்பின் செயல்பாட்டை ஆழமாக ஆராய்வதன் மூலம், த்ரெட்களை மதிப்புகளுக்கு வரைபடமாக்கும் ஒரு வரைபடத்தை நாம் கற்பனை செய்யலாம், தற்போதைய நூல் அதைப் பயன்படுத்த வேண்டியிருக்கும் போது பொருத்தமான மதிப்பை எடுக்கும்.

ThreadLocal class கன்ஸ்ட்ரக்டர்

கன்ஸ்ட்ரக்டர் செயல்
ThreadLocal() ஜாவாவில் ஒரு வெற்று மாறியை உருவாக்குகிறது

முறைகள்

முறை செயல்
பெறு() தற்போதைய தொடரிழையின் உள்ளூர் மாறியின் மதிப்பை வழங்கும்
தொகுப்பு () தற்போதைய தொடரிழைக்கான உள்ளூர் மாறியின் மதிப்பை அமைக்கிறது
அகற்று() தற்போதைய நூலின் உள்ளூர் மாறியின் மதிப்பை நீக்குகிறது
ThreadLocal.withInitial() ஆரம்ப மதிப்பை அமைக்கும் கூடுதல் தொழிற்சாலை முறை

அமைக்க()

இரண்டு கவுண்டர்களை உருவாக்கும் உதாரணத்தை எழுதுவோம். முதல், ஒரு சாதாரண மாறி, நூல்களின் எண்ணிக்கையை எண்ணுவதற்காக இருக்கும். இரண்டாவது நாம் ஒரு ThreadLocal இல் போர்த்துவோம் . மேலும் அவர்கள் எவ்வாறு இணைந்து செயல்படுகிறார்கள் என்று பார்ப்போம். முதலில், ஒரு ThreadDemo வகுப்பை எழுதுவோம் , அது Runnable ஐப் பெறுகிறது மற்றும் நமது தரவு மற்றும் அனைத்து முக்கியமான ரன்() முறையைக் கொண்டுள்ளது. திரையில் கவுண்டர்களைக் காண்பிக்கும் முறையையும் நாங்கள் சேர்ப்போம்:


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());
    }
}

எங்கள் வகுப்பின் ஒவ்வொரு ஓட்டத்திலும், நாங்கள் அதிகரிக்கிறோம்கவுண்டர்ThreadLocal மாறியிலிருந்து தரவைப் பெறுவதற்கு 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();

}

எங்கள் வகுப்பை இயக்கும் போது, ​​ThreadLocal மாறி அதை அணுகும் நூலைப் பொருட்படுத்தாமல் ஒரே மாதிரியாக இருப்பதைக் காண்கிறோம் , ஆனால் நூல்களின் எண்ணிக்கை வளர்கிறது.

கவுண்டர்: 1
கவுண்டர்: 2
கவுண்டர்: 3
threadLocalCounter: 0 threadLocalCounter
: 0
threadLocalCounter: 0

வெளியேறும் குறியீடு 0 உடன் செயல்முறை முடிந்தது

அகற்று()

அகற்றும் முறை எவ்வாறு செயல்படுகிறது என்பதைப் புரிந்துகொள்ள , ThreadDemo வகுப்பில் உள்ள குறியீட்டை சற்று மாற்றுவோம் :


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

இந்த குறியீட்டில், த்ரெட் கவுண்டர் என்பது இரட்டை எண்ணாக இருந்தால், நமது ThreadLocal மாறியில் உள்ள remove() முறையை அழைப்போம் . விளைவாக:

கவுண்டர்: 3
threadLocalCounter: 0
கவுண்டர்: 2
threadLocalCounter: null
கவுண்டர்: 1
threadLocalCounter: 0

வெளியேறும் குறியீடு 0 உடன் செயல்முறை முடிந்தது

இரண்டாவது திரியில் உள்ள ThreadLocal மாறி பூஜ்யமாக இருப்பதை இங்கு எளிதாகக் காணலாம் .

ThreadLocal.withInitial()

இந்த முறை ஒரு நூல்-உள்ளூர் மாறியை உருவாக்குகிறது.

ThreadDemo வகுப்பை செயல்படுத்துதல் :


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
threadLocalCounter: 1
threadLocalCounter: 1
threadLocalCounter: 1

வெளியேறும் குறியீடு 0 உடன் செயல்முறை முடிந்தது

இத்தகைய மாறிகளை நாம் ஏன் பயன்படுத்த வேண்டும்?

java.lang.Thread செயல்படுத்தும் நூலுடன் தொடர்புடைய உள்ளூர் மாறிகள் மீது ThreadLocal ஒரு சுருக்கத்தை வழங்குகிறது .

ThreadLocal மாறிகள் சாதாரணமானவற்றிலிருந்து வேறுபடுகின்றன, அதில் ஒவ்வொரு திரிக்கும் அதன் சொந்த, தனித்தனியாக துவக்கப்பட்ட மாறியின் நிகழ்வு உள்ளது, இது get() மற்றும் set() முறைகள் வழியாக அணுகப்படுகிறது.

ஒவ்வொரு நூலும், அதாவது த்ரெட் வகுப்பின் உதாரணம், அதனுடன் தொடர்புடைய ThreadLocal மாறிகளின் வரைபடம் உள்ளது . வரைபடத்தின் விசைகள் ThreadLocal பொருள்களுக்கான குறிப்புகளாகும், மேலும் மதிப்புகள் "பெற்ற" ThreadLocal மாறிகளுக்கான குறிப்புகளாகும் .

மல்டித்ரெட் செய்யப்பட்ட பயன்பாடுகளில் ரேண்டம் எண்களை உருவாக்க ரேண்டம் வகுப்பு ஏன் பொருந்தாது?

சீரற்ற எண்களைப் பெற ரேண்டம் வகுப்பைப் பயன்படுத்துகிறோம் . ஆனால் பல திரிக்கப்பட்ட சூழலில் இது நன்றாக வேலை செய்கிறதா? உண்மையில், இல்லை. பல திரிக்கப்பட்ட சூழல்களுக்கு ரேண்டம் பொருந்தாது, ஏனெனில் ஒரே நேரத்தில் ஒரு வகுப்பை பல நூல்கள் அணுகும்போது, ​​செயல்திறன் பாதிக்கப்படுகிறது.

இந்தச் சிக்கலைத் தீர்க்க, JDK 7 ஆனது java.util.concurrent.ThreadLocalRandom வகுப்பை அறிமுகப்படுத்தி, பன்முகத் திரிக்கப்பட்ட சூழலில் சீரற்ற எண்களை உருவாக்குகிறது. இது இரண்டு வகுப்புகளைக் கொண்டுள்ளது: ThreadLocal மற்றும் Random .

ஒரு நூலால் பெறப்பட்ட சீரற்ற எண்கள் மற்ற இழைகளில் இருந்து சுயாதீனமானவை, ஆனால் java.util.Random உலகளாவிய சீரற்ற எண்களை வழங்குகிறது. மேலும், ரேண்டம் போலல்லாமல் , ThreadLocalRandom வெளிப்படையான விதைப்பை ஆதரிக்காது. அதற்குப் பதிலாக, இது ரேண்டமில் இருந்து பெறப்பட்ட setSeed() முறையை மேலெழுதுகிறது , அதனால் அது எப்போதும் அழைக்கப்படும்போது ஆதரிக்கப்படாத ஆபரேஷன்எக்சப்சனை எறிகிறது.

ThreadLocalRandom வகுப்பின் முறைகளைப் பார்ப்போம் :

முறை செயல்
ThreadLocalRandom current() தற்போதைய தொடரிழையின் ThreadLocalRandom ஐ வழங்குகிறது.
int next (int bits) அடுத்த போலி சீரற்ற எண்ணை உருவாக்குகிறது.
இரட்டை அடுத்தது இரட்டை (குறைந்தபட்சம் இரட்டை, இரட்டை பிணைப்பு) குறைந்தபட்சம் (உள்ளடக்கிய) மற்றும் பிணைக்கப்பட்ட (பிரத்தியேகமான) இடையே ஒரே மாதிரியான விநியோகத்திலிருந்து போலி எண்ணை வழங்குகிறது .
int nextInt(int least, int bound) குறைந்தபட்சம் (உள்ளடக்கிய) மற்றும் பிணைக்கப்பட்ட (பிரத்தியேகமான) இடையே ஒரே மாதிரியான விநியோகத்திலிருந்து போலி எண்ணை வழங்குகிறது.
நீண்ட அடுத்தநீளம் (நீண்ட n) 0 (உள்ளடங்கியது) மற்றும் குறிப்பிட்ட மதிப்பு (பிரத்தியேகமானது) ஆகியவற்றுக்கு இடையே உள்ள சீரான விநியோகத்திலிருந்து போலி எண்ணை வழங்கும்.
நீண்ட அடுத்த நீளம் (நீண்ட குறைந்தது, நீண்ட பிணைப்பு) குறைந்தபட்சம் (உள்ளடக்கிய) மற்றும் பிணைக்கப்பட்ட (பிரத்தியேகமான) இடையே ஒரே மாதிரியான விநியோகத்திலிருந்து போலி எண்ணை வழங்குகிறது.
வெற்றிட விதை (நீண்ட விதை) ஆதரிக்கப்படாத OperationException ஐ வீசுகிறது . இந்த ஜெனரேட்டர் விதைப்பை ஆதரிக்காது.

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 உருவாக்கியது
20
த்ரெட் 3 உருவாக்கியது 7228 நூல் உருவாக்கப்பட்டது

இப்போது நமது RandomNumbers வகுப்பை மாற்றி அதில் Random ஐப் பயன்படுத்துவோம் :


int result = new Random().nextInt(bound);
எடுக்கப்பட்ட நேரம்: 5
நூல் 20 உருவாக்கியது 48
நூல் 19 உருவாக்கியது 57
நூல் 18 உருவாக்கியது 90
நூல் 22 உருவாக்கியது 43
நூல் 24 உருவாக்கியது 7
நூல் 23 உருவாக்கியது 63
நூல் 15 உருவாக்கியது 2
நூல் 16 உருவாக்கியது
40
நூல் 1 2917 உருவாக்கப்பட்டது

குறிப்பு எடுக்க! எங்கள் சோதனைகளில், சில சமயங்களில் முடிவுகள் ஒரே மாதிரியாகவும் சில சமயங்களில் வித்தியாசமாகவும் இருக்கும். ஆனால் நாம் அதிக நூல்களைப் பயன்படுத்தினால் (சொல்லுங்கள், 100), முடிவு இப்படி இருக்கும்:

ரேண்டம் — 19-25 ms
ThreadLocalRandom — 17-19 ms

அதன்படி, எங்கள் பயன்பாட்டில் அதிகமான நூல்கள், மல்டித்ரெட் சூழலில் ரேண்டம் வகுப்பைப் பயன்படுத்தும் போது செயல்திறன் அதிகமாகும் .

ரேண்டம் மற்றும் த்ரெட்லோக்கல் ரேண்டம் வகுப்புகளுக்கு இடையே உள்ள வேறுபாடுகளை சுருக்கவும் மீண்டும் வலியுறுத்தவும் :

சீரற்ற ThreadLocalRandom
ரேண்டமின் ஒரே நிகழ்வை வெவ்வேறு திரிகள் பயன்படுத்தினால் , முரண்பாடுகள் மற்றும் செயல்திறன் பாதிக்கப்படும். எந்த முரண்பாடுகளும் சிக்கல்களும் இல்லை, ஏனெனில் உருவாக்கப்பட்ட சீரற்ற எண்கள் தற்போதைய தொடரிழையில் உள்ளமையாகும்.
ஆரம்ப மதிப்பை மாற்ற, நேரியல் ஒத்த சூத்திரத்தைப் பயன்படுத்துகிறது. சீரற்ற எண் ஜெனரேட்டர் உள்நாட்டில் உருவாக்கப்பட்ட விதையைப் பயன்படுத்தி துவக்கப்படுகிறது.
ஒவ்வொரு நூலும் அதன் சொந்த ரேண்டம் பொருள்களைப் பயன்படுத்தும் பயன்பாடுகளில் பயனுள்ளதாக இருக்கும் . த்ரெட் பூல்களில் இணையாக பல இழைகள் சீரற்ற எண்களைப் பயன்படுத்தும் பயன்பாடுகளில் பயனுள்ளதாக இருக்கும்.
இது ஒரு பெற்றோர் வகுப்பு. இது ஒரு குழந்தை வகுப்பு.