ఈ పాఠంలో, మేము సాధారణంగా java.lang.ThreadLocal<> క్లాస్‌తో పని చేయడం గురించి మరియు మల్టీథ్రెడ్ వాతావరణంలో దీన్ని ఎలా ఉపయోగించాలి అనే దాని గురించి మాట్లాడుతాము .

ThreadLocal క్లాస్ వేరియబుల్స్ నిల్వ చేయడానికి ఉపయోగించబడుతుంది. ఈ తరగతి యొక్క విలక్షణమైన లక్షణం ఏమిటంటే, ఇది ఉపయోగించిన ప్రతి థ్రెడ్‌కు విలువ యొక్క ప్రత్యేక స్వతంత్ర కాపీని ఉంచుతుంది.

తరగతి యొక్క ఆపరేషన్‌ను లోతుగా పరిశీలిస్తే, థ్రెడ్‌లను విలువలకు మ్యాప్ చేసే మ్యాప్‌ను మనం ఊహించవచ్చు , ప్రస్తుత థ్రెడ్ దానిని ఉపయోగించాల్సిన అవసరం వచ్చినప్పుడు దాని నుండి తగిన విలువను తీసుకుంటుంది.

ThreadLocal క్లాస్ కన్స్ట్రక్టర్

కన్స్ట్రక్టర్ చర్య
ThreadLocal() జావాలో ఖాళీ వేరియబుల్‌ని సృష్టిస్తుంది

పద్ధతులు

పద్ధతి చర్య
పొందండి() ప్రస్తుత థ్రెడ్ యొక్క లోకల్ వేరియబుల్ విలువను అందిస్తుంది
సెట్ () ప్రస్తుత థ్రెడ్ కోసం స్థానిక వేరియబుల్ విలువను సెట్ చేస్తుంది
తొలగించు() ప్రస్తుత థ్రెడ్ యొక్క స్థానిక వేరియబుల్ విలువను తొలగిస్తుంది
ThreadLocal.withInitial() ప్రారంభ విలువను సెట్ చేసే అదనపు ఫ్యాక్టరీ పద్ధతి

తయారుగా ఉండండి()

మేము రెండు కౌంటర్లను సృష్టించే ఉదాహరణను వ్రాస్దాం. మొదటిది, సాధారణ వేరియబుల్, థ్రెడ్‌ల సంఖ్యను లెక్కించడానికి ఉంటుంది. రెండవది మేము థ్రెడ్‌లోకల్‌లో వ్రాప్ చేస్తాము . మరి వీరిద్దరూ ఎలా కలిసి పని చేస్తారో చూడాలి. ముందుగా, రన్ చేయదగినది మరియు మన డేటా మరియు అన్ని ముఖ్యమైన రన్() పద్ధతిని కలిగి ఉండే థ్రెడ్‌డెమో క్లాస్‌ని వ్రాద్దాం . స్క్రీన్‌పై కౌంటర్‌లను ప్రదర్శించడానికి మేము ఒక పద్ధతిని కూడా జోడిస్తాము:


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

}

మా తరగతిని నడుపుతున్నప్పుడు, థ్రెడ్‌లోకల్ వేరియబుల్ యాక్సెస్ చేసే థ్రెడ్‌తో సంబంధం లేకుండా అలాగే ఉంటుందని మేము చూస్తాము , కానీ థ్రెడ్‌ల సంఖ్య పెరుగుతుంది.

కౌంటర్: 1
కౌంటర్: 2
కౌంటర్: 3
థ్రెడ్‌లోకల్ కౌంటర్: 0
థ్రెడ్‌లోకల్ కౌంటర్: 0
థ్రెడ్‌లోకల్ కౌంటర్: 0

నిష్క్రమణ కోడ్ 0తో ప్రక్రియ పూర్తయింది

తొలగించు()

తీసివేత పద్ధతి ఎలా పనిచేస్తుందో అర్థం చేసుకోవడానికి , మేము ThreadDemo క్లాస్‌లో కోడ్‌ని కొద్దిగా మారుస్తాము :


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.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
థ్రెడ్‌లోకల్ కౌంటర్: 1
థ్రెడ్‌లోకల్ కౌంటర్: 1
థ్రెడ్‌లోకల్ కౌంటర్: 1

నిష్క్రమణ కోడ్ 0తో ప్రక్రియ పూర్తయింది

అటువంటి వేరియబుల్స్ ఎందుకు ఉపయోగించాలి?

అమలు java.lang.Thread థ్రెడ్‌కు సంబంధించి థ్రెడ్‌లోకల్ స్థానిక వేరియబుల్స్‌పై సంగ్రహాన్ని అందిస్తుంది .

ThreadLocal వేరియబుల్స్ సాధారణ వాటి నుండి భిన్నంగా ఉంటాయి, ప్రతి థ్రెడ్ దాని స్వంత, వ్యక్తిగతంగా ప్రారంభించబడిన వేరియబుల్ యొక్క ఉదాహరణను కలిగి ఉంటుంది, ఇది get () మరియు set() పద్ధతుల ద్వారా యాక్సెస్ చేయబడుతుంది.

ప్రతి థ్రెడ్, అంటే థ్రెడ్ క్లాస్ యొక్క ఉదాహరణ, దానితో అనుబంధించబడిన ThreadLocal వేరియబుల్స్ యొక్క మ్యాప్‌ను కలిగి ఉంటుంది . మ్యాప్ యొక్క కీలు ThreadLocal ఆబ్జెక్ట్‌లకు రిఫరెన్స్‌లు మరియు విలువలు "పొందిన" ThreadLocal వేరియబుల్స్‌కు సూచనలు.

మల్టీథ్రెడ్ అప్లికేషన్‌లలో యాదృచ్ఛిక సంఖ్యలను రూపొందించడానికి రాండమ్ క్లాస్ ఎందుకు సరిపోదు?

యాదృచ్ఛిక సంఖ్యలను పొందడానికి మేము రాండమ్ తరగతిని ఉపయోగిస్తాము. అయితే ఇది మల్టీథ్రెడ్ వాతావరణంలో అలాగే పని చేస్తుందా? నిజానికి, లేదు. బహుళ థ్రెడ్ వాతావరణాలకు యాదృచ్ఛికం తగినది కాదు, ఎందుకంటే బహుళ థ్రెడ్‌లు ఒకే సమయంలో తరగతిని యాక్సెస్ చేసినప్పుడు, పనితీరు దెబ్బతింటుంది.

ఈ సమస్యను పరిష్కరించడానికి, JDK 7 బహుళ థ్రెడ్ వాతావరణంలో యాదృచ్ఛిక సంఖ్యలను రూపొందించడానికి java.util.concurrent.ThreadLocalRandom తరగతిని ప్రవేశపెట్టింది. ఇది రెండు తరగతులను కలిగి ఉంటుంది: థ్రెడ్‌లోకల్ మరియు రాండమ్ .

ఒక థ్రెడ్ ద్వారా స్వీకరించబడిన యాదృచ్ఛిక సంఖ్యలు ఇతర థ్రెడ్‌ల నుండి స్వతంత్రంగా ఉంటాయి, అయితే java.util.Random ప్రపంచవ్యాప్తంగా యాదృచ్ఛిక సంఖ్యలను అందిస్తుంది. అలాగే, రాండమ్ వలె కాకుండా , ThreadLocalRandom స్పష్టమైన సీడింగ్‌కు మద్దతు ఇవ్వదు. బదులుగా, ఇది రాండమ్ నుండి సంక్రమించిన setSeed() పద్ధతిని ఓవర్‌రైడ్ చేస్తుంది , తద్వారా ఇది ఎల్లప్పుడూ కాల్ చేసినప్పుడు మద్దతు లేని ఆపరేషన్ ఎక్సెప్షన్‌ను విసురుతుంది.

ThreadLocalRandom తరగతి యొక్క పద్ధతులను చూద్దాం :

పద్ధతి చర్య
ThreadLocalRandom కరెంట్() ప్రస్తుత థ్రెడ్ యొక్క ThreadLocalRandomని అందిస్తుంది.
int తదుపరి (int బిట్స్) తదుపరి సూడో-యాదృచ్ఛిక సంఖ్యను రూపొందిస్తుంది.
డబుల్ నెక్స్ట్ డబుల్ (కనీసం డబుల్, డబుల్ బౌండ్) కనిష్ట (కలిసి) మరియు కట్టుబడి (ప్రత్యేకమైన) మధ్య ఏకరీతి పంపిణీ నుండి సూడోరాండమ్ సంఖ్యను అందిస్తుంది .
int nextInt (int మినిమం, Int బౌండ్) కనిష్ట (కలిసి) మరియు కట్టుబడి (ప్రత్యేకమైన) మధ్య ఏకరీతి పంపిణీ నుండి సూడోరాండమ్ సంఖ్యను అందిస్తుంది.
లాంగ్ నెక్స్ట్ లాంగ్(లాంగ్ ఎన్) 0 (కలిసి) మరియు పేర్కొన్న విలువ (ప్రత్యేకమైన) మధ్య ఏకరీతి పంపిణీ నుండి సూడోరాండమ్ సంఖ్యను అందిస్తుంది.
లాంగ్ నెక్స్ట్ లాంగ్ (దీర్ఘమైన, లాంగ్ బౌండ్) కనిష్ట (కలిసి) మరియు కట్టుబడి (ప్రత్యేకమైన) మధ్య ఏకరీతి పంపిణీ నుండి సూడోరాండమ్ సంఖ్యను అందిస్తుంది.
శూన్యమైన సెట్ సీడ్ (పొడవైన విత్తనం) మద్దతు లేని ఆపరేషన్ మినహాయింపును విసిరివేస్తుంది . ఈ జనరేటర్ విత్తనాలకు మద్దతు ఇవ్వదు.

ThreadLocalRandom.current()ని ఉపయోగించి యాదృచ్ఛిక సంఖ్యలను పొందడం

ThreadLocalRandom అనేది ThreadLocal మరియు రాండమ్ తరగతుల కలయిక. ఇది యాదృచ్ఛిక తరగతికి సంబంధించిన ఉదంతాలకు ఏదైనా ఏకకాల ప్రాప్యతను నివారించడం ద్వారా మల్టీథ్రెడ్ వాతావరణంలో మెరుగైన పనితీరును సాధిస్తుంది.

బహుళ థ్రెడ్‌లతో కూడిన ఒక ఉదాహరణను అమలు చేయండి మరియు మా అప్లికేషన్ 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 రూపొందించబడింది 728 థ్రెడ్ 3 రూపొందించబడింది



మరియు ఇప్పుడు మన రాండమ్ నంబర్‌ల తరగతిని మారుద్దాం మరియు అందులో రాండమ్‌ని ఉపయోగిస్తాము:


int result = new Random().nextInt(bound);
తీసుకున్న సమయం: 5
థ్రెడ్ 20 రూపొందించబడింది 48
థ్రెడ్ 19 రూపొందించబడింది 57
థ్రెడ్ 18 రూపొందించబడింది 90
థ్రెడ్ 22 రూపొందించబడింది 43
థ్రెడ్ 24 రూపొందించబడింది 7
థ్రెడ్ 23 రూపొందించబడింది 63
థ్రెడ్ 15 రూపొందించబడింది 2
థ్రెడ్ 16 రూపొందించబడింది 40
థ్రెడ్ 1 రూపొందించబడింది 29
17 రూపొందించబడింది

గమనించండి! మా పరీక్షలలో, కొన్నిసార్లు ఫలితాలు ఒకేలా ఉంటాయి మరియు కొన్నిసార్లు అవి భిన్నంగా ఉంటాయి. కానీ మేము మరిన్ని థ్రెడ్‌లను ఉపయోగిస్తే (చెప్పండి, 100), ఫలితం ఇలా కనిపిస్తుంది:

రాండమ్ — 19-25 ms
ThreadLocalRandom — 17-19 ms

దీని ప్రకారం, మా అప్లికేషన్‌లో ఎక్కువ థ్రెడ్‌లు ఉంటే, మల్టీథ్రెడ్ వాతావరణంలో రాండమ్ క్లాస్‌ని ఉపయోగిస్తున్నప్పుడు పనితీరు ఎక్కువ అవుతుంది .

రాండమ్ మరియు థ్రెడ్‌లోకల్ రాండమ్ తరగతుల మధ్య వ్యత్యాసాలను సంగ్రహించడానికి మరియు పునరుద్ఘాటించడానికి :

యాదృచ్ఛికంగా ThreadLocalRandom
విభిన్న థ్రెడ్‌లు రాండమ్ యొక్క ఒకే ఉదాహరణను ఉపయోగిస్తే , వైరుధ్యాలు ఏర్పడతాయి మరియు పనితీరు దెబ్బతింటుంది. వైరుధ్యాలు లేదా సమస్యలు లేవు, ఎందుకంటే ఉత్పత్తి చేయబడిన యాదృచ్ఛిక సంఖ్యలు ప్రస్తుత థ్రెడ్‌కు స్థానికంగా ఉంటాయి.
ప్రారంభ విలువను మార్చడానికి సరళ సమరూప సూత్రాన్ని ఉపయోగిస్తుంది. యాదృచ్ఛిక సంఖ్య జనరేటర్ అంతర్గతంగా ఉత్పత్తి చేయబడిన విత్తనాన్ని ఉపయోగించి ప్రారంభించబడుతుంది.
ప్రతి థ్రెడ్ దాని స్వంత రాండమ్ ఆబ్జెక్ట్‌లను ఉపయోగించే అప్లికేషన్‌లలో ఉపయోగపడుతుంది . బహుళ థ్రెడ్‌లు థ్రెడ్ పూల్స్‌లో సమాంతరంగా యాదృచ్ఛిక సంఖ్యలను ఉపయోగించే అప్లికేషన్‌లలో ఉపయోగకరంగా ఉంటుంది.
ఇది తల్లిదండ్రుల తరగతి. ఇది పిల్లల తరగతి.