మీకు 1 థ్రెడ్ కోసం ఎగ్జిక్యూటర్ సర్వీస్ ఎందుకు అవసరం కావచ్చు?

మీరు ఒకే థ్రెడ్‌ని కలిగి ఉన్న పూల్‌తో ExecutorServiceని సృష్టించడానికి Executors.newSingleThreadExecutor పద్ధతిని ఉపయోగించవచ్చు . పూల్ యొక్క తర్కం క్రింది విధంగా ఉంది:

  • సేవ ఒక సమయంలో ఒక పనిని మాత్రమే అమలు చేస్తుంది.
  • మేము అమలు కోసం N టాస్క్‌లను సమర్పించినట్లయితే, అన్ని N టాస్క్‌లు ఒకే థ్రెడ్ ద్వారా ఒకదాని తర్వాత ఒకటి అమలు చేయబడతాయి.
  • థ్రెడ్‌కు అంతరాయం ఏర్పడితే, మిగిలిన టాస్క్‌లను అమలు చేయడానికి కొత్త థ్రెడ్ సృష్టించబడుతుంది.

మా ప్రోగ్రామ్‌కు కింది కార్యాచరణ అవసరమయ్యే పరిస్థితిని ఊహించుకుందాం:

మేము వినియోగదారు అభ్యర్థనలను 30 సెకన్లలోపు ప్రాసెస్ చేయాలి, కానీ యూనిట్ సమయానికి ఒకటి కంటే ఎక్కువ అభ్యర్థనలు ఉండవు.

వినియోగదారు అభ్యర్థనను ప్రాసెస్ చేయడం కోసం మేము టాస్క్ క్లాస్‌ని సృష్టిస్తాము:


class Task implements Runnable {
   private final int taskNumber;

   public Task(int taskNumber) {
       this.taskNumber = taskNumber;
   }

   @Override
   public void run() {
       try {
           Thread.sleep(1000);
       } catch (InterruptedException ignored) {
       }
       System.out.printf("Processed request #%d on thread id=%d\\n", taskNumber, Thread.currentThread().getId());
   }
}
    

తరగతి ఇన్‌కమింగ్ అభ్యర్థనను ప్రాసెస్ చేసే ప్రవర్తనను మోడల్ చేస్తుంది మరియు దాని సంఖ్యను ప్రదర్శిస్తుంది.

తరువాత, ప్రధాన పద్ధతిలో, మేము 1 థ్రెడ్ కోసం ExecutorService ని సృష్టిస్తాము , మేము ఇన్‌కమింగ్ అభ్యర్థనలను వరుసగా ప్రాసెస్ చేయడానికి ఉపయోగిస్తాము. విధి పరిస్థితులు "30 సెకన్లలోపు" అని నిర్దేశిస్తున్నందున, మేము 30-సెకన్ల నిరీక్షణను జోడించి, ఆపై బలవంతంగా ExecutorServiceని ఆపివేస్తాము .


public static void main(String[] args) throws InterruptedException {
   ExecutorService executorService = Executors.newSingleThreadExecutor();

   for (int i = 0; i < 1_000; i++) {
       executorService.execute(new Task(i));
   }
   executorService.awaitTermination(30, TimeUnit.SECONDS);
   executorService.shutdownNow();
}
    

ప్రోగ్రామ్‌ను ప్రారంభించిన తర్వాత, కన్సోల్ అభ్యర్థన ప్రాసెసింగ్ గురించి సందేశాలను ప్రదర్శిస్తుంది:

థ్రెడ్ ఐడిలో #0 అభ్యర్థన ప్రాసెస్ చేయబడింది=16
థ్రెడ్ ఐడిలో #1 అభ్యర్థన ప్రాసెస్ చేయబడింది=16
థ్రెడ్ ఐడిలో #2 ప్రాసెస్ చేయబడిన అభ్యర్థన = 16

థ్రెడ్ ఐడిలో #29 అభ్యర్థనను ప్రాసెస్ చేయబడింది=16

30 సెకన్ల పాటు అభ్యర్థనలను ప్రాసెస్ చేసిన తర్వాత, executorService shutdownNow() పద్ధతిని పిలుస్తుంది , ఇది ప్రస్తుత టాస్క్‌ను (ఎక్స్‌క్యూట్ చేయబడుతోంది) ఆపివేస్తుంది మరియు పెండింగ్‌లో ఉన్న అన్ని టాస్క్‌లను రద్దు చేస్తుంది. ఆ తరువాత, కార్యక్రమం విజయవంతంగా ముగుస్తుంది.

కానీ ప్రతిదీ ఎల్లప్పుడూ అంత పరిపూర్ణంగా ఉండదు, ఎందుకంటే మా పూల్ యొక్క ఏకైక థ్రెడ్ ద్వారా ఎంపిక చేయబడిన టాస్క్‌లలో ఒకటి తప్పుగా పని చేస్తుంది మరియు మా థ్రెడ్‌ను కూడా ముగించే పరిస్థితిని మా ప్రోగ్రామ్ సులభంగా కలిగి ఉంటుంది. ఈ సందర్భంలో ఒకే థ్రెడ్‌తో executorService ఎలా పని చేస్తుందో గుర్తించడానికి మేము ఈ పరిస్థితిని అనుకరించవచ్చు .

దీన్ని చేయడానికి, టాస్క్‌లలో ఒకదానిని అమలు చేస్తున్నప్పుడు, మేము సురక్షితం కాని మరియు వాడుకలో లేని Thread.currentThread().stop() పద్ధతిని ఉపయోగించి మా థ్రెడ్‌ను ముగించాము. టాస్క్‌లలో ఒకటి థ్రెడ్‌ను ముగించే పరిస్థితిని అనుకరించడానికి మేము ఉద్దేశపూర్వకంగా దీన్ని చేస్తున్నాము.

మేము టాస్క్ క్లాస్‌లో రన్ పద్ధతిని మారుస్తాము :


@Override
public void run() {
   try {
       Thread.sleep(1000);
   } catch (InterruptedException ignored) {
   }

   if (taskNumber == 5) {
       Thread.currentThread().stop();
   }

   System.out.printf("Processed request #%d on thread id=%d\\n", taskNumber, Thread.currentThread().getId());
}
    

మేము టాస్క్ #5కి అంతరాయం కలిగిస్తాము.

టాస్క్ #5 చివరిలో అంతరాయం కలిగించిన థ్రెడ్‌తో అవుట్‌పుట్ ఎలా ఉంటుందో చూద్దాం:

థ్రెడ్ ఐడిలో ప్రాసెస్ చేయబడిన అభ్యర్థన #0 = 16
థ్రెడ్ ఐడిలో ప్రాసెస్ చేయబడిన అభ్యర్థన #1 = 16
థ్రెడ్ ఐడిలో ప్రాసెస్ చేయబడిన అభ్యర్థన #2 = 16
ప్రాసెస్ చేయబడిన అభ్యర్థన # థ్రెడ్ ఐడిలో # 16
ప్రాసెస్ చేయబడిన అభ్యర్థన #4 థ్రెడ్ ఐడిలో = 16
ప్రాసెస్ చేయబడిన అభ్యర్థన #6 ఆన్ థ్రెడ్ ఐడి = 17
థ్రెడ్ ఐడిలో #7 అభ్యర్థన ప్రాసెస్ చేయబడింది = 17

థ్రెడ్ ఐడిలో #29 అభ్యర్థన ప్రాసెస్ చేయబడింది = 17

టాస్క్ 5 ముగింపులో థ్రెడ్‌కు అంతరాయం ఏర్పడిన తర్వాత, టాస్క్‌లు ఐడెంటిఫైయర్ 17 ఉన్న థ్రెడ్‌లో అమలు చేయడం ప్రారంభమవుతుందని మేము చూస్తాము, అయితే అవి గతంలో ఐడెంటిఫైయర్ 16తో థ్రెడ్‌లో అమలు చేయబడ్డాయి. మరియు మా పూల్‌లో ఒక సింగిల్ థ్రెడ్, దీని అర్థం ఒక్కటే: executorService ఆపివేసిన థ్రెడ్‌ను కొత్త దానితో భర్తీ చేసింది మరియు టాస్క్‌లను అమలు చేయడం కొనసాగించింది.

అందువల్ల, మేము పనులను వరుసగా మరియు ఒక సమయంలో మాత్రమే ప్రాసెస్ చేయాలనుకున్నప్పుడు సింగిల్-థ్రెడ్ పూల్‌తో newSingleThreadExecutorని ఉపయోగించాలి మరియు మునుపటి పనిని పూర్తి చేసినప్పటికీ (ఉదా. ఒక సందర్భం) క్యూ నుండి మేము టాస్క్‌లను ప్రాసెస్ చేయాలనుకుంటున్నాము. మా పనులు థ్రెడ్‌ను చంపుతాయి).

థ్రెడ్‌ఫ్యాక్టరీ

థ్రెడ్‌లను సృష్టించడం మరియు పునఃసృష్టి చేయడం గురించి మాట్లాడేటప్పుడు, మేము ప్రస్తావించకుండా ఉండలేముథ్రెడ్‌ఫ్యాక్టరీ.

థ్రెడ్‌ఫ్యాక్టరీడిమాండ్‌పై కొత్త థ్రెడ్‌లను సృష్టించే వస్తువు.

మేము మా స్వంత థ్రెడ్ సృష్టి కర్మాగారాన్ని సృష్టించవచ్చు మరియు దాని యొక్క ఉదాహరణను Executors.newSingleThreadExecutor (ThreadFactory threadFactory) పద్ధతికి పంపవచ్చు.


ExecutorService executorService = Executors.newSingleThreadExecutor(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "MyThread");
            }
        });
                    
మేము కొత్త థ్రెడ్‌ను సృష్టించే పద్ధతిని భర్తీ చేస్తాము, థ్రెడ్ పేరును కన్స్ట్రక్టర్‌కు పంపుతాము.

ExecutorService executorService = Executors.newSingleThreadExecutor(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r, "MyThread");
                thread.setPriority(Thread.MAX_PRIORITY);
                return thread;
            }
        });
                    
మేము సృష్టించిన థ్రెడ్ పేరు మరియు ప్రాధాన్యతను మార్చాము.

కాబట్టి మనకు 2 ఓవర్‌లోడ్ చేయబడిన Executors.newSingleThreadExecutor పద్ధతులు ఉన్నాయని మేము చూస్తాము . పారామితులు లేకుండా ఒకటి, మరియు రెండవది ThreadFactory పరామితితో.

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