ఒక సాధారణ ప్రోగ్రామ్‌ను పరిగణించండి:


public static void main(String[] args) throws Exception {
	// Create an ExecutorService with a fixed number of threads: three
	ExecutorService service = Executors.newFixedThreadPool(3);
 
	// Pass a simple Runnable task to the ExecutorService
	service.submit(() -> System.out.println("done"));
}

ప్రోగ్రామ్‌ని అమలు చేయడం వలన మనం ఆశించే కన్సోల్ అవుట్‌పుట్ ఉత్పత్తి అవుతుంది:

పూర్తి

అయితే దీనిని మనం సాధారణంగా IntelliJ IDEAలో చూసే అవుట్‌పుట్ అనుసరించదు:

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

ఒక ప్రోగ్రామ్ ముగిసినప్పుడు మనం సాధారణంగా చూస్తాము.

అలా ఎందుకు జరుగుతుంది?

ExecutorService ని ఉపయోగించి సృష్టించబడిన థ్రెడ్‌లు స్పష్టంగా నిలిపివేయబడే వరకు ఉనికిలో కొనసాగుతాయని newFixedThreadPool() పద్ధతి యొక్క వివరణ తెలియజేస్తుంది . అంటే మేము ఒక పనిని ExecutorServiceకి పంపినందున , దాన్ని అమలు చేయడానికి ఒక థ్రెడ్ సృష్టించబడింది మరియు ఆ థ్రెడ్ పని పూర్తయిన తర్వాత కూడా ఉనికిలో ఉంటుంది.

ఎగ్జిక్యూటర్ సర్వీస్‌లో ఆపివేయడం

ఫలితంగా, మేము ExecutorServiceని "షట్ డౌన్" (లేదా ఆపివేయాలి) చేయాలి . మేము దీన్ని రెండు విధాలుగా చేయవచ్చు:

  1. void shutdown() — ఈ పద్ధతిని పిలిచిన తర్వాత, ExecutorService కొత్త ఉద్యోగాలను అంగీకరించడాన్ని ఆపివేస్తుంది. ఎగ్జిక్యూటర్ సర్వీస్‌కు గతంలో సమర్పించిన అన్ని టాస్క్‌లు అమలులో కొనసాగుతాయి.

    
    public static void main(String[] args) throws Exception {
    ExecutorService service = Executors.newFixedThreadPool(3);
        	service.submit(() -> System.out.println("task 1"));
        	service.submit(() -> System.out.println("task 2"));
        	service.shutdown();
        	// A RejectedExecutionException will occur here
        	service.submit(() -> System.out.println("task 3"));
    }
    
  2. List<Runnable> shutdownNow() — ఈ పద్ధతి ప్రస్తుతం సక్రియంగా ఉన్న ఉద్యోగాలను ఆపడానికి ప్రయత్నిస్తుంది. ఇప్పటికీ తమ వంతు కోసం వేచి ఉన్న టాస్క్‌లు విస్మరించబడతాయి మరియు అమలు చేయదగిన వాటి జాబితాగా అందించబడతాయి .

    
    public static void main(String[] args) throws Exception {
        ExecutorService service = Executors.newFixedThreadPool(5);
        List.of(1, 2, 3, 4, 5, 6, 7, 8).forEach(i -> service.submit(() -> System.out.println(i)));
        List<Runnable> runnables = service.shutdownNow();
        runnables.forEach(System.out::println);
    }
    

అవుట్‌పుట్:

1
2
4
3
java.util.concurrent.FutureTask@1e80bfe8[పూర్తి కాలేదు, టాస్క్ = java.util.concurrent.Executors$RunnableAdapter@4edde6e5[ర్యాప్డ్ టాస్క్ = Test$$Lambda$16/0x0000d]700000000001
ప్రస్తుత .FutureTask@cc34f4d[పూర్తి కాలేదు, టాస్క్ = java.util.concurrent.Executors$RunnableAdapter@66a29884[ర్యాప్డ్ టాస్క్ = టెస్ట్$$లాంబ్డా$16/0x0000000800b95040@479b]జ 9caf[
పూర్తి కాలేదు, పని = java.util.concurrent.Executors$RunnableAdapter@17a7cec2[Wrapped task = Test$$Lambda$16/0x0000000800b95040@65b3120a]]
5

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

అవుట్‌పుట్ రన్ నుండి రన్‌కు భిన్నంగా ఉంటుంది. అవుట్‌పుట్‌లో 2 రకాల పంక్తులు ఉన్నాయి:

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

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

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

ఇతర పద్ధతులు

ExecutorService దీన్ని ఆపడానికి సంబంధించిన అనేక ఇతర పద్ధతులను కలిగి ఉంది:

  1. boolean awaitTermination(దీర్ఘ సమయం ముగిసింది, TimeUnit యూనిట్) — ఈ పద్ధతి దానిని పిలిచే థ్రెడ్‌ను బ్లాక్ చేస్తుంది. కింది మూడు ఈవెంట్‌లలో ఏదైనా ఒకటి సంభవించిన వెంటనే బ్లాక్ ముగుస్తుంది:

    • shutdown() పద్ధతిని పిలిచిన తర్వాత , అన్ని సక్రియ ఉద్యోగాలు మరియు అన్ని షెడ్యూల్ చేసిన పనులు అమలు చేయబడ్డాయి;
    • పద్ధతి పారామితుల ద్వారా నిర్ణయించబడిన సమయం ముగిసింది;
    • awaitTermination() పద్ధతిని పిలిచే థ్రెడ్ రద్దు చేయబడింది.

    గడువు ముగిసేలోపు ExecutorService ఆపివేయబడితే ఈ పద్ధతి ఒప్పు అని మరియు గడువు ఇప్పటికే ముగిసినట్లయితే తప్పు అని చూపబడుతుంది .

    
    public static void main(String[] args) throws Exception {
    	ExecutorService service = Executors.newFixedThreadPool(2);
    	service.submit(() -> System.out.println("task 1"));
    	service.submit(() -> System.out.println("task 2"));
    	service.submit(() -> System.out.println("task 3"));
    	service.shutdown();
    	System.out.println(service.awaitTermination(1, TimeUnit.MICROSECONDS));
    }
    
  2. boolean isShutdown() — shutdown () లేదా shutdownNow() పద్ధతిని ఎగ్జిక్యూటర్‌సర్వీస్‌లో పిలిస్తే నిజం అని చూపుతుంది .

    
    public static void main(String[] args) throws Exception {
    	ExecutorService service = Executors.newFixedThreadPool(2);
    	service.submit(() -> System.out.println("task 1"));
    	service.submit(() -> System.out.println("task 2"));
    	service.submit(() -> System.out.println("task 3"));
    	System.out.println(service.isShutdown());
    	service.shutdown();
    	System.out.println(service.isShutdown());
    }
    
  3. boolean isTerminated()ఎగ్జిక్యూటర్‌సర్వీస్‌లో షట్‌డౌన్ () లేదా shutdownNow() పద్ధతిని పిలిస్తే మరియు అన్ని టాస్క్‌లు పూర్తి అయినట్లయితే, నిజమని చూపుతుంది.

    
    public static void main(String[] args) throws Exception {
        ExecutorService service = Executors.newFixedThreadPool(5);
        List.of(1, 2, 3, 4, 5, 6, 7, 8).forEach(i -> service.submit(() -> System.out.println(i)));
        service.shutdownNow();
        System.out.println(service.isTerminated());
    }
    

ఈ పద్ధతులను ఉపయోగించే ఉదాహరణ కోడ్:


public static void main(String[] args) throws Exception {
   ExecutorService service = Executors.newFixedThreadPool(16);
   Callable<String> task = () -> {
       Thread.sleep(1);
       return "Done";
   };
 
   // Add 10,000 tasks to the queue
   List<Future<String>> futures = IntStream.range(0, 10_000)
           .mapToObj(i -> service.submit(task))
           .collect(Collectors.toList());
   System.out.printf("%d tasks were submitted for execution.%n", futures.size());
 
   // Attempt to shut down
   service.shutdown();
   // Wait 100 milliseconds to finish the work
   if (service.awaitTermination(100, TimeUnit.MILLISECONDS)) {
       System.out.println("All tasks completed!");
   } else {
       // Stop forcibly
       List<Runnable> notExecuted = service.shutdownNow();
       System.out.printf("%d tasks were not started.%n", notExecuted.size());
   }
 
   System.out.printf("Total tasks completed: %d.%n", futures.stream().filter(Future::isDone).count());
}

అవుట్‌పుట్ (పరుగు నుండి పరుగుకు భిన్నంగా ఉంటుంది):

10,000 టాస్క్‌లు అమలు కోసం సమర్పించబడ్డాయి.
9170 పనులు ప్రారంభం కాలేదు.
పూర్తి చేసిన మొత్తం పనులు: 830 పనులు.

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