మీకు ఎగ్జిక్యూటర్ ఇంటర్‌ఫేస్ ఎందుకు అవసరం?

జావా 5కి ముందు, మీరు మీ అప్లికేషన్‌లో మీ స్వంత కోడ్ థ్రెడ్ మేనేజ్‌మెంట్ మొత్తాన్ని వ్రాయవలసి ఉంటుంది. అదనంగా, సృష్టించడం aకొత్త థ్రెడ్ఆబ్జెక్ట్ అనేది రిసోర్స్-ఇంటెన్సివ్ ఆపరేషన్, మరియు ప్రతి తేలికైన పని కోసం కొత్త థ్రెడ్‌ని సృష్టించడం సమంజసం కాదు. మరియు ఈ సమస్య మల్టీ-థ్రెడ్ అప్లికేషన్‌ల యొక్క ప్రతి డెవలపర్‌కు ఖచ్చితంగా తెలిసినందున, వారు ఈ కార్యాచరణను జావాలోకి ఎగ్జిక్యూటర్ ఫ్రేమ్‌వర్క్‌గా తీసుకురావాలని నిర్ణయించుకున్నారు .

పెద్ద ఆలోచన ఏమిటి? ఇది చాలా సులభం: ప్రతి కొత్త పనికి కొత్త థ్రెడ్‌ని సృష్టించే బదులు, థ్రెడ్‌లు ఒక రకమైన "స్టోరేజ్"లో ఉంచబడతాయి మరియు కొత్త టాస్క్ వచ్చినప్పుడు, మేము కొత్తదాన్ని సృష్టించే బదులు ఇప్పటికే ఉన్న థ్రెడ్‌ను తిరిగి పొందుతాము.

ఈ ఫ్రేమ్‌వర్క్ యొక్క ప్రధాన ఇంటర్‌ఫేస్‌లు ఎగ్జిక్యూటర్ , ఎగ్జిక్యూటర్ సర్వీస్ మరియు షెడ్యూల్డ్ ఎగ్జిక్యూటర్ సర్వీస్ , వీటిలో ప్రతి ఒక్కటి మునుపటి కార్యాచరణను విస్తరించింది.

ఎగ్జిక్యూటర్ ఇంటర్‌ఫేస్ అనేది బేస్ ఇంటర్‌ఫేస్. ఇది అమలు చేయగల ఆబ్జెక్ట్ ద్వారా అమలు చేయబడిన ఒకే శూన్యమైన అమలు (రన్ చేయదగిన కమాండ్) పద్ధతిని ప్రకటించింది .

ExecutorService ఇంటర్‌ఫేస్ మరింత ఆసక్తికరంగా ఉంటుంది . ఇది పనిని పూర్తి చేయడానికి, అలాగే ఒక రకమైన ఫలితాన్ని తిరిగి ఇచ్చే పద్ధతులను నిర్వహించడానికి పద్ధతులను కలిగి ఉంది. దాని పద్ధతులను మరింత వివరంగా పరిశీలిద్దాం:

పద్ధతి వివరణ
శూన్యమైన షట్డౌన్ (); ఈ పద్ధతికి కాల్ చేయడం వలన ExecutorService ఆపివేయబడుతుంది . ప్రాసెసింగ్ కోసం ఇప్పటికే సమర్పించబడిన అన్ని టాస్క్‌లు పూర్తవుతాయి, కానీ కొత్త టాస్క్‌లు ఆమోదించబడవు.
జాబితా<రన్ చేయదగిన> shutdownNow();

ఈ పద్ధతికి కాల్ చేయడం వలన ExecutorService ఆపివేయబడుతుంది . ఇప్పటికే ప్రాసెసింగ్ కోసం సమర్పించబడిన అన్ని టాస్క్‌లకు Thread.interrupt కాల్ చేయబడుతుంది. ఈ పద్ధతి క్యూలో ఉన్న టాస్క్‌ల జాబితాను అందిస్తుంది.

పద్ధతిని పిలిచే సమయంలో "పురోగతిలో ఉన్న" అన్ని పనులు పూర్తయ్యే వరకు ఈ పద్ధతి వేచి ఉండదు.

హెచ్చరిక: ఈ పద్ధతికి కాల్ చేయడం వలన వనరులు లీక్ కావచ్చు.

boolean isShutdown(); ఎగ్జిక్యూటర్ సర్వీస్ నిలిపివేయబడిందో లేదో తనిఖీ చేస్తుంది .
బూలియన్ isTerminated(); ExecutorService షట్‌డౌన్ తర్వాత అన్ని టాస్క్‌లు పూర్తయితే ఒప్పు అని చూపబడుతుంది . shutdown() లేదా shutdownNow() అని పిలిచే వరకు , ఇది ఎల్లప్పుడూ తప్పుగా తిరిగి వస్తుంది .
బూలియన్ నిరీక్షణ ముగింపు (దీర్ఘ సమయం ముగిసింది, టైమ్‌యూనిట్ యూనిట్) అంతరాయానికి మినహాయింపు;

షట్‌డౌన్() పద్ధతిని పిలిచిన తర్వాత , కింది షరతుల్లో ఒకటి నిజం అయ్యే వరకు ఈ పద్ధతి దానిని పిలిచే థ్రెడ్‌ను బ్లాక్ చేస్తుంది:

  • షెడ్యూల్ చేయబడిన అన్ని పనులు పూర్తయ్యాయి;
  • పద్ధతికి గడువు ముగిసిన సమయం ముగిసింది;
  • ప్రస్తుత థ్రెడ్ అంతరాయం కలిగింది.

అన్ని టాస్క్‌లు పూర్తయితే ఒప్పు అని మరియు ముగింపుకు ముందు గడువు ముగిసినట్లయితే తప్పు అని చూపబడుతుంది .

<T> భవిష్యత్తు<T> సమర్పించండి(కాల్ చేయగల<T> టాస్క్);

ఎగ్జిక్యూటర్‌సర్వీస్‌కు కాల్ చేయదగిన టాస్క్‌ని జోడిస్తుంది మరియు ఫ్యూచర్ ఇంటర్‌ఫేస్‌ను అమలు చేసే వస్తువును అందిస్తుంది .

<T> అనేది పాస్ చేసిన టాస్క్ యొక్క ఫలితం రకం.

<T> భవిష్యత్తు<T> సమర్పించండి (రన్ చేయదగిన పని, T ఫలితం);

ఎగ్జిక్యూటర్‌సర్వీస్‌కు రన్ చేయదగిన టాస్క్‌ని జోడిస్తుంది మరియు ఫ్యూచర్ ఇంటర్‌ఫేస్‌ను అమలు చేసే వస్తువును అందిస్తుంది .

T ఫలితం పరామితి అనేది ఒక కాల్ ద్వారా ఫలితాన్ని పొందే () పద్ధతికి తిరిగి వస్తుందిభవిష్యత్తు వస్తువు.

భవిష్యత్తు<?> సమర్పించండి(రన్ చేయదగిన పని);

ఎగ్జిక్యూటర్‌సర్వీస్‌కు రన్ చేయదగిన టాస్క్‌ని జోడిస్తుంది మరియు ఫ్యూచర్ ఇంటర్‌ఫేస్‌ను అమలు చేసే వస్తువును అందిస్తుంది .

ఫలితంగా వచ్చే ఫ్యూచర్ ఆబ్జెక్ట్‌పై మనం get() పద్ధతిని కాల్ చేస్తే , మనకు శూన్యం వస్తుంది.

<T> జాబితా<భవిష్యత్<T>> ఇన్‌వోక్‌అల్(సేకరణ<? కాల్ చేయదగిన<T>> టాస్క్‌లను పొడిగిస్తుంది) InterruptedExceptionని విసిరివేస్తుంది;

కాల్ చేయదగిన టాస్క్‌ల జాబితాను ఎగ్జిక్యూటర్‌సర్వీస్‌కి పంపుతుంది . మేము పని ఫలితాన్ని పొందగల భవిష్యత్తుల జాబితాను అందిస్తుంది. సమర్పించిన పనులన్నీ పూర్తయిన తర్వాత ఈ జాబితా తిరిగి ఇవ్వబడుతుంది.

పద్ధతి అమలులో ఉన్నప్పుడు టాస్క్‌ల సేకరణ సవరించబడితే, ఈ పద్ధతి యొక్క ఫలితం నిర్వచించబడదు.

<T> జాబితా<భవిష్యత్తు<T>> invokeAll(సేకరణ<? కాల్ చేయదగిన<T>> టాస్క్‌లను పొడిగిస్తుంది, ఎక్కువ సమయం ముగిసింది, TimeUnit యూనిట్) InterruptedExceptionని విసురుతుంది;

కాల్ చేయదగిన పనుల జాబితాను ఎగ్జిక్యూటర్ సర్వీస్‌కి పంపుతుంది . మేము పని ఫలితాన్ని పొందగల భవిష్యత్తుల జాబితాను అందిస్తుంది. ఆమోదించబడిన అన్ని పనులు పూర్తయినప్పుడు లేదా పద్ధతికి గడువు ముగిసిన తర్వాత, ఏది ముందుగా వచ్చినా ఈ జాబితా తిరిగి ఇవ్వబడుతుంది.

గడువు ముగిసినట్లయితే, అసంపూర్తిగా ఉన్న పనులు రద్దు చేయబడతాయి.

గమనిక: రద్దు చేయబడిన పని అమలును ఆపివేయకపోవచ్చు (మేము ఈ దుష్ప్రభావాన్ని ఉదాహరణలో చూస్తాము).

పద్ధతి అమలులో ఉన్నప్పుడు టాస్క్‌ల సేకరణ సవరించబడితే, ఈ పద్ధతి యొక్క ఫలితం నిర్వచించబడదు.

<T> T invokeAny(సేకరణ<? కాల్ చేయగల<T>> టాస్క్‌లను పొడిగిస్తుంది) InterruptedException, ExecutionException;

కాల్ చేయదగిన పనుల జాబితాను ఎగ్జిక్యూటర్ సర్వీస్‌కి పంపుతుంది . మినహాయింపు (ఏదైనా ఉంటే) లేకుండా పూర్తి చేసిన టాస్క్‌లలో ఒకదాని (ఏదైనా ఉంటే) ఫలితాన్ని అందిస్తుంది.

పద్ధతి అమలులో ఉన్నప్పుడు టాస్క్‌ల సేకరణ సవరించబడితే, ఈ పద్ధతి యొక్క ఫలితం నిర్వచించబడదు.

<T> T invokeAny(కలెక్షన్<? కాల్ చేయదగిన<T>> టాస్క్‌లను పొడిగిస్తుంది, ఎక్కువ సమయం ముగిసింది, TimeUnit యూనిట్) InterruptedException, ExecutionException, TimeoutException;

కాల్ చేయదగిన పనుల జాబితాను ఎగ్జిక్యూటర్ సర్వీస్‌కి పంపుతుంది . పద్ధతికి గడువు ముగిసిన సమయం ముగిసేలోపు మినహాయింపు లేకుండా పూర్తి చేసిన టాస్క్‌లలో ఒకదాని (ఏదైనా ఉంటే) ఫలితాన్ని అందిస్తుంది.

పద్ధతి అమలులో ఉన్నప్పుడు టాస్క్‌ల సేకరణ సవరించబడితే, ఈ పద్ధతి యొక్క ఫలితం నిర్వచించబడదు.

ExecutorService తో పని చేయడానికి ఒక చిన్న ఉదాహరణను చూద్దాం .


import java.util.List;
import java.util.concurrent.*;

public class ExecutorServiceTest {
   public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
//Create an ExecutorService for 2 threads
       java.util.concurrent.ExecutorService executorService = new ThreadPoolExecutor(2, 2, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
// Create 5 tasks
       MyRunnable task1 = new MyRunnable();
       MyRunnable task2 = new MyRunnable();
       MyRunnable task3 = new MyRunnable();
       MyRunnable task4 = new MyRunnable();
       MyRunnable task5 = new MyRunnable();

       final List<MyRunnable> tasks = List.of(task1, task2, task3, task4, task5);
// Pass a list that contains the 5 tasks we created
       final List<Future<Void>> futures = executorService.invokeAll(tasks, 6, TimeUnit.SECONDS);
       System.out.println("Futures received");

// Stop the ExecutorService
       executorService.shutdown();

       try {
           TimeUnit.SECONDS.sleep(3);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       System.out.println(executorService.isShutdown());
       System.out.println(executorService.isTerminated());
   }

   public static class MyRunnable implements Callable<Void> {

       @Override
       public void call() {
// Add 2 delays. When the ExecutorService is stopped, we will see which delay is in progress when the attempt is made to stop execution of the task
           try {
               TimeUnit.SECONDS.sleep(3);
           } catch (InterruptedException e) {
               System.out.println("sleep 1: " + e.getMessage());
           }
           try {
               TimeUnit.SECONDS.sleep(2);
           } catch (InterruptedException e) {
               System.out.println("sleep 2: " + e.getMessage());
           }
           System.out.println("done");
           return null;
       }
   }
}

అవుట్‌పుట్:

పూర్తయింది ఫ్యూచర్స్ స్లీప్ పొందింది 1: నిద్రకు అంతరాయం కలిగించింది నిద్ర 1: నిద్రకు
అంతరాయం కలిగింది నిజం నిజం






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

ప్రోగ్రామ్ ప్రారంభమైన ఆరు సెకన్ల తర్వాత, ఇన్వోక్ ఆల్ మెథడ్ సమయం ముగిసింది మరియు ఫలితం ఫ్యూచర్‌ల జాబితాగా అందించబడుతుంది . ఫ్యూచర్స్ అందుకున్న అవుట్‌పుట్ స్ట్రింగ్ నుండి ఇది చూడవచ్చు .

మొదటి రెండు పనులు పూర్తయిన తర్వాత మరో రెండు పనులు ప్రారంభమవుతాయి. కానీ invokeAll పద్ధతిలో సెట్ చేసిన గడువు ముగిసినందున, ఈ రెండు టాస్క్‌లను పూర్తి చేయడానికి సమయం లేదు. వారు "రద్దు" ఆదేశాన్ని అందుకుంటారు. అందుకే అవుట్‌పుట్‌లో స్లీప్ 1తో రెండు లైన్లు ఉన్నాయి: నిద్రకు అంతరాయం .

ఆపై మీరు పూర్తి చేసిన మరో రెండు పంక్తులను చూడవచ్చు . InvokeAll పద్ధతిని వివరించేటప్పుడు నేను పేర్కొన్న సైడ్ ఎఫెక్ట్ ఇది .

ఐదవ మరియు చివరి టాస్క్ ఎప్పటికీ ప్రారంభించబడదు, కాబట్టి అవుట్‌పుట్‌లో దాని గురించి మనకు ఏమీ కనిపించదు.

చివరి రెండు పంక్తులు isShutdown మరియు isTerminated పద్ధతులకు కాల్ చేయడం వలన ఏర్పడినవి .

ఈ ఉదాహరణను డీబగ్ మోడ్‌లో అమలు చేయడం మరియు గడువు ముగిసిన తర్వాత విధి స్థితిని చూడటం కూడా ఆసక్తికరంగా ఉంటుంది ( executorService.shutdown(); ) తో లైన్‌లో బ్రేక్‌పాయింట్‌ను సెట్ చేయండి ):

మేము రెండు పనులు సాధారణంగా పూర్తయినట్లు మరియు మూడు టాస్క్‌లు "రద్దు" అయినట్లు చూస్తాము .

షెడ్యూల్డ్ ఎగ్జిక్యూటర్ సర్వీస్

కార్యనిర్వాహకుల గురించి మా చర్చను ముగించడానికి, ScheduledExecutorService ని పరిశీలిద్దాం .

దీనికి 4 పద్ధతులు ఉన్నాయి:

పద్ధతి వివరణ
పబ్లిక్ షెడ్యూల్డ్ ఫ్యూచర్<?> షెడ్యూల్ (రన్ చేయదగిన కమాండ్, చాలా ఆలస్యం, టైమ్‌యూనిట్ యూనిట్); ఆర్గ్యుమెంట్‌గా పేర్కొన్న ఆలస్యం తర్వాత ఒకసారి అమలు చేయడానికి ఆమోదించబడిన అమలు చేయదగిన పనిని షెడ్యూల్ చేస్తుంది .
పబ్లిక్ <V> షెడ్యూల్డ్ ఫ్యూచర్<V> షెడ్యూల్ (కాల్ చేయగల<V> కాల్ చేయదగినది, చాలా ఆలస్యం, టైమ్‌యూనిట్ యూనిట్); ఆర్గ్యుమెంట్‌గా పేర్కొన్న ఆలస్యం తర్వాత ఒకసారి అమలు చేయడానికి ఆమోదించబడిన కాల్ చేయదగిన పనిని షెడ్యూల్ చేస్తుంది.
పబ్లిక్ షెడ్యూల్డ్ ఫ్యూచర్<?> షెడ్యూల్AtFixedRate(రన్ చేయదగిన కమాండ్, దీర్ఘ ప్రారంభ ఆలస్యం, దీర్ఘకాలం, టైమ్‌యూనిట్ యూనిట్); పాస్ అయిన టాస్క్ యొక్క ఆవర్తన అమలును షెడ్యూల్ చేస్తుంది, ఇది ప్రారంభ ఆలస్యం తర్వాత మొదటిసారిగా అమలు చేయబడుతుంది మరియు ప్రతి తదుపరి పరుగు వ్యవధి తర్వాత ప్రారంభమవుతుంది .
పబ్లిక్ షెడ్యూల్డ్ ఫ్యూచర్<?> షెడ్యూల్‌తో ఫిక్స్డ్ డిలే(రన్ చేయదగిన కమాండ్, దీర్ఘ ప్రారంభ ఆలస్యం, చాలా ఆలస్యం, టైమ్‌యూనిట్ యూనిట్); పాస్ అయిన టాస్క్ యొక్క కాలానుగుణ అమలును షెడ్యూల్ చేస్తుంది, ఇది ప్రారంభ ఆలస్యం తర్వాత మొదటిసారిగా అమలు చేయబడుతుంది మరియు ప్రతి తదుపరి పరుగు ఆలస్యం తర్వాత ప్రారంభమవుతుంది (మునుపటి రన్ పూర్తి మరియు ప్రస్తుత ప్రారంభం మధ్య కాలం).