একটি সহজ প্রোগ্রাম বিবেচনা করুন:


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]0108070800007]java.
বর্তমান .FutureTask@cc34f4d[সম্পূর্ণ হয়নি, টাস্ক = java.util.concurrent.Executors$RunnableAdapter@66a29884[মোড়ানো টাস্ক = Test$$Lambda$16/0x0000000800b95040@b95040@b000000800b95040@4769b]6f.concurrent]6f.concurrent. 9caf [সম্পূর্ণ হয়নি
, টাস্ক = java.util.concurrent.Executors$RunnableAdapter@17a7cec2[মোড়ানো টাস্ক = টেস্ট$$Lambda$16/0x0000000800b95040@65b3120a]]
5

প্রস্থান কোড 0 সহ প্রক্রিয়া সমাপ্ত

রান থেকে রানে আউটপুট আলাদা হবে। আউটপুটে 2 ধরণের লাইন রয়েছে:

  • একটি সংখ্যার মানে হল যে ExecutorService সংশ্লিষ্ট টাস্কটি প্রক্রিয়া করতে পরিচালিত হয়েছে, আমরা টাস্ক তৈরি করতে যে তালিকাটি ব্যবহার করেছি তা থেকে নম্বরটি প্রদর্শন করে।

  • একটি FutureTask অবজেক্টে toString() পদ্ধতিতে কল করার ফলাফল । এই অবজেক্টগুলি এমন কাজ যা এক্সিকিউটরসার্ভিসে জমা দেওয়া হয়েছিল কিন্তু প্রক্রিয়া করা হয়নি।

আউটপুট আরেকটি আকর্ষণীয় nuance আছে. একটি আদর্শ বিশ্বে, আমরা প্রথমে সমস্ত প্রদর্শিত সংখ্যা দেখতে পাব, তারপরে FutureTask অবজেক্টগুলি দেখতে পাব। কিন্তু সিঙ্ক্রোনাইজেশন সমস্যাগুলি আউটপুটে লাইনগুলিকে এলোমেলো করে দেয়।

অন্যান্য পদ্ধতি

ExecutorService এটি বন্ধ করার সাথে সম্পর্কিত আরও বেশ কয়েকটি পদ্ধতি রয়েছে:

  1. বুলিয়ান ওয়েটটার্মিনেশন (লং টাইমআউট, টাইমইউনিট ইউনিট) — এই পদ্ধতিটি থ্রেডটিকে ব্লক করে যা এটিকে কল করে। নিম্নলিখিত তিনটি ঘটনার যেকোনো একটি ঘটলেই ব্লকটি শেষ হয়ে যায়:

    • 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. বুলিয়ান 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. executorService- এ shutdown () বা shutdownNow() মেথড কল করা হলে এবং সমস্ত কাজ সম্পন্ন হলে বুলিয়ান isTerminated() - সত্যে ফিরে আসে ।

    
    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 দিয়ে প্রক্রিয়া শেষ হয়েছে