एक साधा प्रोग्राम विचारात घ्या:


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 सह प्रक्रिया पूर्ण झाली

जेव्हा एखादा कार्यक्रम संपतो तेव्हा आपण हे सहसा पाहतो.

असे का होते?

newFixedThreadPool() पद्धतीचे वर्णन आम्हाला सांगते की ExecutorService वापरून तयार केलेले थ्रेड्स स्पष्टपणे थांबेपर्यंत अस्तित्वात राहतात. याचा अर्थ असा की आम्ही ExecutorService ला टास्क पास केल्यामुळे , ते कार्यान्वित करण्यासाठी एक थ्रेड तयार केला गेला आणि तो थ्रेड कार्य पूर्ण झाल्यानंतरही अस्तित्वात आहे.

ExecutorService येथे थांबत आहे

परिणामी, आम्हाला ExecutorService "बंद" (किंवा थांबवणे) आवश्यक आहे . आम्ही हे दोन प्रकारे करू शकतो:

  1. void shutdown() — ही पद्धत कॉल केल्यानंतर, ExecutorService नवीन नोकर्‍या स्वीकारणे थांबवते. 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/0x000000ecd]09.08000007]708000000000707508000cd
वर्तमान .FutureTask@cc34f4d[पूर्ण झाले नाही, टास्क = java.util.concurrent.Executors$RunnableAdapter@66a29884[रॅप्ड टास्क = Test$$Lambda$16/0x0000000800b95040@b95040@b4769b]
java.concurrent]50040@b0769b00rent. 9caf[पूर्ण झाले नाही, कार्य = java.util.concurrent.Executors$RunnableAdapter@17a7cec2[रॅप्ड टास्क = Test$$Lambda$16/0x0000000800b95040@65b3120a]]
5

बाहेर पडा कोड 0 सह प्रक्रिया पूर्ण झाली

आउटपुट रन टू रन वेगळे असेल. आउटपुटमध्ये 2 प्रकारच्या ओळी आहेत:

  • संख्या म्हणजे एक्झिक्युटर सर्व्हिसने संबंधित कार्यावर प्रक्रिया करणे व्यवस्थापित केले, आम्ही कार्ये तयार करण्यासाठी वापरलेल्या सूचीमधून क्रमांक प्रदर्शित करतो.

  • FutureTask ऑब्जेक्टवर toString() पद्धत कॉल केल्याचे परिणाम . हे ऑब्जेक्ट्स अशी कार्ये आहेत जी एक्झिक्युटर सर्व्हिसला सबमिट केली गेली होती परंतु त्यावर प्रक्रिया केली गेली नव्हती.

आउटपुटमध्ये आणखी एक मनोरंजक सूक्ष्मता आहे. आदर्श जगात, आम्ही प्रथम सर्व प्रदर्शित संख्या पाहू, त्यानंतर FutureTask ऑब्जेक्ट्स. परंतु सिंक्रोनाइझेशन समस्या आउटपुटमधील रेषा गोंधळतात.

इतर पद्धती

ExecutorService मध्ये ते थांबवण्याशी संबंधित आणखी अनेक पद्धती आहेत:

  1. बूलियन awaitTermination(लाँग टाइमआउट, टाइमयुनिट युनिट) — ही पद्धत कॉल करणाऱ्या थ्रेडला ब्लॉक करते. खालील तीनपैकी कोणतीही एक घटना घडताच ब्लॉक संपेल:

    • 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()ExecutorService वर 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()executorService वर shutdown() किंवा 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 सह प्रक्रिया पूर्ण झाली