কেন আপনি এক্সিকিউটর ইন্টারফেস প্রয়োজন?

জাভা 5 এর আগে, আপনাকে আপনার অ্যাপ্লিকেশনে আপনার নিজস্ব কোড থ্রেড পরিচালনা লিখতে হয়েছিল। উপরন্তু, একটি তৈরিনতুন সূত্রঅবজেক্ট একটি সম্পদ-নিবিড় অপারেশন, এবং প্রতিটি লাইটওয়েট কাজের জন্য একটি নতুন থ্রেড তৈরি করা মানে না। এবং যেহেতু এই সমস্যাটি মাল্টি-থ্রেডেড অ্যাপ্লিকেশনগুলির প্রতিটি বিকাশকারীর কাছে পরিচিত, তাই তারা এই কার্যকারিতাটিকে এক্সিকিউটর ফ্রেমওয়ার্ক হিসাবে জাভাতে আনার সিদ্ধান্ত নিয়েছে।

বড় ধারণা কি? এটি সহজ: প্রতিটি নতুন টাস্কের জন্য একটি নতুন থ্রেড তৈরি করার পরিবর্তে, থ্রেডগুলি এক ধরণের "স্টোরেজ" এ রাখা হয় এবং যখন একটি নতুন টাস্ক আসে, আমরা একটি নতুন তৈরি করার পরিবর্তে একটি বিদ্যমান থ্রেড পুনরুদ্ধার করি।

এই ফ্রেমওয়ার্কের প্রধান ইন্টারফেসগুলি হল এক্সিকিউটর , এক্সিকিউটরসার্ভিস এবং নির্ধারিত এক্সিকিউটরসার্ভিস , যার প্রত্যেকটিই আগেরটির কার্যকারিতা প্রসারিত করে৷

এক্সিকিউটর ইন্টারফেস হল বেস ইন্টারফেস। এটি একটি একক অকার্যকর কার্যকরী (চালানযোগ্য কমান্ড) পদ্ধতি ঘোষণা করে যা একটি রানযোগ্য বস্তু দ্বারা প্রয়োগ করা হয়।

ExecutorService ইন্টারফেস আরো আকর্ষণীয় . এটিতে কাজ সমাপ্তি পরিচালনা করার পদ্ধতি রয়েছে, পাশাপাশি কিছু ধরণের ফলাফল ফেরত দেওয়ার পদ্ধতি রয়েছে। আসুন এর পদ্ধতিগুলি ঘনিষ্ঠভাবে দেখে নেওয়া যাক:

পদ্ধতি বর্ণনা
অকার্যকর শাটডাউন(); এই পদ্ধতিতে কল করা ExecutorService বন্ধ করে দেয় । ইতিমধ্যে প্রক্রিয়াকরণের জন্য জমা দেওয়া সমস্ত কাজ সম্পন্ন করা হবে, তবে নতুন কাজগুলি গ্রহণ করা হবে না।
তালিকা<Runnable> shutdownNow();

এই পদ্ধতিতে কল করা ExecutorService বন্ধ করে দেয় । ইতিমধ্যে প্রক্রিয়াকরণের জন্য জমা দেওয়া সমস্ত কাজের জন্য Thread.interrupt কল করা হবে। এই পদ্ধতিটি সারিবদ্ধ কাজের একটি তালিকা প্রদান করে।

পদ্ধতিটি কল করার সময় "প্রগতিতে" থাকা সমস্ত কাজ সমাপ্তির জন্য অপেক্ষা করে না।

সতর্কতা: এই পদ্ধতিতে কল করলে রিসোর্স লিক হতে পারে।

বুলিয়ান isShutdown(); ExecutorService বন্ধ করা হয়েছে কিনা তা পরীক্ষা করে ।
বুলিয়ান isTerminated(); ExecutorService বন্ধ করার পরে সমস্ত কাজ সম্পন্ন হলে সত্য দেখায় । যতক্ষণ না shutdown() বা shutdownNow() বলা হয়, এটি সর্বদা মিথ্যা ফিরে আসবে ।
বুলিয়ান ওয়েটটার্মিনেশন (লং টাইমআউট, টাইমইউনিট ইউনিট) বাধাপ্রাপ্ত ব্যতিক্রম নিক্ষেপ করে;

shutdown() পদ্ধতিটি কল করার পরে , নিম্নলিখিত শর্তগুলির মধ্যে একটি সত্য না হওয়া পর্যন্ত এই পদ্ধতিটি থ্রেডটিকে ব্লক করে যা এটি বলা হয়:

  • সমস্ত নির্ধারিত কাজ সম্পূর্ণ;
  • পদ্ধতিতে পাস করা সময় শেষ হয়ে গেছে;
  • বর্তমান থ্রেড বাধাপ্রাপ্ত হয়.

সমস্ত কাজ সম্পূর্ণ হলে সত্য দেখায় , এবং মেয়াদ শেষ হওয়ার আগে শেষ হয়ে গেলে মিথ্যা দেখায় ।

<T> ভবিষ্যত<T> জমা (কলযোগ্য<T> টাস্ক);

ExecutorService- এ একটি কলযোগ্য টাস্ক যোগ করে এবং একটি বস্তু ফেরত দেয় যা ভবিষ্যত ইন্টারফেস প্রয়োগ করে।

<T> হল পাস করা টাস্কের ফলাফলের ধরন।

<T> ভবিষ্যত<T> জমা দিন (চালানযোগ্য টাস্ক, টি ফলাফল);

ExecutorService- এ একটি রানযোগ্য টাস্ক যোগ করে এবং একটি বস্তু ফেরত দেয় যা ভবিষ্যত ইন্টারফেস প্রয়োগ করে।

T ফলাফল পরামিতি হল ফলাফলে get() পদ্ধতিতে কল করার মাধ্যমে যা ফিরে আসেভবিষ্যতের বস্তু।

ভবিষ্যত<?> জমা দেওয়া (চালানো যোগ্য টাস্ক);

ExecutorService- এ একটি রানযোগ্য টাস্ক যোগ করে এবং একটি বস্তু ফেরত দেয় যা ভবিষ্যত ইন্টারফেস প্রয়োগ করে।

আমরা যদি ফলাফলযুক্ত Future অবজেক্টে get() মেথড কল করি , তাহলে আমরা null পাব।

<T> তালিকা<ভবিষ্যত<T>> invokeAll(সংগ্রহ<? প্রসারিত Callable<T>> কাজগুলি) InterruptedException নিক্ষেপ করে;

এক্সিকিউটরসার্ভিসে কলযোগ্য কাজের একটি তালিকা পাস করে । ফিউচারের একটি তালিকা দেখায় যেখান থেকে আমরা কাজের ফলাফল পেতে পারি। জমা দেওয়া সমস্ত কাজ শেষ হলে এই তালিকাটি ফেরত দেওয়া হয়।

পদ্ধতিটি চলাকালীন যদি কার্য সংগ্রহ পরিবর্তন করা হয়, এই পদ্ধতির ফলাফল অনির্ধারিত।

<T> তালিকা<ভবিষ্যত<T>> ইনভোকঅল(সংগ্রহ<? কলযোগ্য<T>> কাজগুলিকে প্রসারিত করে, দীর্ঘ সময়সীমা, টাইমইউনিট ইউনিট) বাধাপ্রাপ্ত এক্সসেপশন নিক্ষেপ করে;

এক্সিকিউটরসার্ভিসে কলযোগ্য কাজের একটি তালিকা পাস করে । ফিউচারের একটি তালিকা দেখায় যেখান থেকে আমরা কাজের ফলাফল পেতে পারি। এই তালিকাটি ফেরত দেওয়া হয় যখন সমস্ত পাস করা কাজ সম্পন্ন হয়, বা পদ্ধতিতে পাস করার সময় শেষ হয়ে যায়, যেটি প্রথমে আসে।

যদি সময় শেষ হয়ে যায়, অসমাপ্ত কাজগুলি বাতিল করা হয়।

দ্রষ্টব্য: এটা সম্ভব যে একটি বাতিল কাজ চালানো বন্ধ হবে না (আমরা উদাহরণে এই পার্শ্ব প্রতিক্রিয়া দেখতে পাব)।

পদ্ধতিটি চলাকালীন যদি কার্য সংগ্রহ পরিবর্তন করা হয়, এই পদ্ধতির ফলাফল অনির্ধারিত।

<T> T invokeAny(সংগ্রহ<? প্রসারিত Callable<T>> কাজগুলি) InterruptedException, ExecutionException নিক্ষেপ করে;

এক্সিকিউটরসার্ভিসে কলযোগ্য কাজের একটি তালিকা পাস করে । একটি ব্যতিক্রম (যদি থাকে) ছাড়াই সম্পন্ন করা একটি কাজের (যদি থাকে) ফলাফল প্রদান করে।

পদ্ধতিটি চলাকালীন যদি কার্য সংগ্রহ পরিবর্তন করা হয়, এই পদ্ধতির ফলাফল অনির্ধারিত।

<T> T invokeAny(সংগ্রহ<? প্রসারিত করে Callable<T>> কাজগুলি, দীর্ঘ সময়সীমা, টাইমইউনিট ইউনিট) 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> কলযোগ্য, দীর্ঘ বিলম্ব, টাইমইউনিট ইউনিট); একটি আর্গুমেন্ট হিসাবে নির্দিষ্ট বিলম্বের পরে একবার চালানোর জন্য পাস করা কলযোগ্য টাস্কের সময়সূচী করে।
পাবলিক Scheduled Future<?> scheduleAtFixedRate(চালানযোগ্য কমান্ড, দীর্ঘ প্রাথমিক বিলম্ব, দীর্ঘ সময়কাল, টাইমইউনিট ইউনিট); পাস করা টাস্কের পর্যায়ক্রমিক সম্পাদনের সময়সূচী, যা প্রাথমিক বিলম্বের পরে প্রথমবার কার্যকর করা হবে , এবং প্রতিটি পরবর্তী রান পিরিয়ডের পরে শুরু হবে ।
public Scheduled Future<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit ইউনিট); পাস করা টাস্কের পর্যায়ক্রমিক সম্পাদনের সময়সূচী, যা প্রাথমিক বিলম্বের পরে প্রথমবারের জন্য কার্যকর করা হবে , এবং প্রতিটি পরবর্তী রান বিলম্বের পরে শুরু হবে (আগের রানের সমাপ্তি এবং বর্তমানের শুরুর মধ্যে সময়কাল)।