আরেকটি ধরনের থ্রেড পুল হল "ক্যাশেড"। এই ধরনের থ্রেড পুল ঠিক যেমন সাধারণভাবে স্থির হিসাবে ব্যবহৃত হয়.

নাম দ্বারা নির্দেশিত হিসাবে, এই ধরনের থ্রেড পুল থ্রেড ক্যাশে. এটি অব্যবহৃত থ্রেডগুলিকে সীমিত সময়ের জন্য জীবিত রাখে যাতে সেই থ্রেডগুলিকে নতুন কার্য সম্পাদনের জন্য পুনরায় ব্যবহার করা যায়। এই ধরনের একটি থ্রেড পুল আমাদের কিছু যুক্তিসঙ্গত পরিমাণ হালকা কাজ করার জন্য সবচেয়ে ভাল।

"কিছু যুক্তিসঙ্গত পরিমাণ" এর অর্থ বরং বিস্তৃত, তবে আপনার জানা উচিত যে এই জাতীয় পুল প্রতিটি সংখ্যক কাজের জন্য উপযুক্ত নয়। উদাহরণস্বরূপ, ধরুন আমরা এক মিলিয়ন টাস্ক তৈরি করতে চাই। এমনকি প্রতিটিতে খুব অল্প পরিমাণে সময় লাগলেও, আমরা এখনও অযৌক্তিক পরিমাণ সম্পদ ব্যবহার করব এবং কর্মক্ষমতা হ্রাস করব। আমাদের এই ধরনের পুলগুলি এড়ানো উচিত যখন মৃত্যুদন্ড কার্যকর করার সময় অপ্রত্যাশিত হয়, উদাহরণস্বরূপ, I/O টাস্কগুলির সাথে।

হুডের নিচে, ThreadPoolExecutor কনস্ট্রাক্টরকে নিম্নলিখিত আর্গুমেন্ট দিয়ে ডাকা হয়:


public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, 
      new SynchronousQueue<Runnable>());
}

নিম্নলিখিত মানগুলি কনস্ট্রাক্টরের কাছে আর্গুমেন্ট হিসাবে প্রেরণ করা হয়:

প্যারামিটার মান
corePoolSize ( নির্বাহক পরিষেবা শুরু হলে কতগুলি থ্রেড প্রস্তুত (শুরু) হবে ) 0
MaxPoolSize (একজন নির্বাহক পরিষেবা তৈরি করতে পারে এমন সর্বাধিক সংখ্যক থ্রেড ) পূর্ণসংখ্যা।MAX_VALUE
KeepAliveTime ( কোরপুল সাইজের চেয়ে থ্রেডের সংখ্যা বেশি হলে ধ্বংস হওয়ার আগে একটি মুক্ত থ্রেড বেঁচে থাকার সময় ) 60L
একক (সময়ের একক) TimeUnit.SECONDS
কাজের সারি (একটি সারির বাস্তবায়ন) নতুন সিঙ্ক্রোনাস সারি<Runnable>()

এবং আমরা ঠিক একই ভাবে ThreadFactory এর নিজস্ব বাস্তবায়ন পাস করতে পারি ।

আসুন SynchronousQueue সম্পর্কে কথা বলি

একটি সিঙ্ক্রোনাস ট্রান্সফারের প্রাথমিক ধারণাটি বেশ সহজ এবং এখনও কাউন্টার-ইন্টুইটিভ (অর্থাৎ, অন্তর্জ্ঞান বা সাধারণ জ্ঞান আপনাকে বলে যে এটি ভুল): আপনি একটি সারিতে একটি উপাদান যোগ করতে পারেন যদি এবং শুধুমাত্র যদি অন্য থ্রেড এ উপাদানটি গ্রহণ করে । একই সময়. অন্য কথায়, একটি সিঙ্ক্রোনাস কিউতে টাস্ক থাকতে পারে না, কারণ একটি নতুন টাস্ক আসার সাথে সাথে এক্সিকিউটিং থ্রেড ইতিমধ্যে টাস্কটি তুলে নিয়েছে

যখন একটি নতুন কাজ সারিতে প্রবেশ করে, যদি পুলে একটি বিনামূল্যে সক্রিয় থ্রেড থাকে, তাহলে এটি কাজটি তুলে নেয়। যদি সমস্ত থ্রেড ব্যস্ত থাকে, তাহলে একটি নতুন থ্রেড তৈরি করা হয়।

একটি ক্যাশে করা পুল শূন্য থ্রেড দিয়ে শুরু হয় এবং সম্ভাব্যভাবে Integer.MAX_VALUE থ্রেডে বাড়তে পারে ৷ মূলত, একটি ক্যাশে থ্রেড পুলের আকার শুধুমাত্র সিস্টেম সংস্থান দ্বারা সীমাবদ্ধ।

সিস্টেম রিসোর্স সংরক্ষণ করতে, ক্যাশে করা থ্রেড পুল এক মিনিটের জন্য নিষ্ক্রিয় থাকা থ্রেডগুলি সরিয়ে দেয়।

চলুন দেখি কিভাবে এটি অনুশীলনে কাজ করে। আমরা একটি টাস্ক ক্লাস তৈরি করব যা একটি ব্যবহারকারীর অনুরোধের মডেল:


public class Task implements Runnable {
   int taskNumber;

   public Task(int taskNumber) {
       this.taskNumber = taskNumber;
   }

   @Override
   public void run() {
       System.out.println("Processed user request #" + taskNumber + " on thread " + Thread.currentThread().getName());
   }
}
    

মূল পদ্ধতিতে, আমরা নতুন ক্যাশেড থ্রেডপুল তৈরি করি এবং তারপরে সম্পাদনের জন্য 3টি কাজ যোগ করি এখানে আমরা আমাদের পরিষেবার অবস্থা (1) প্রিন্ট করি ।

এর পরে, আমরা 30 সেকেন্ডের জন্য বিরতি দিই, অন্য কাজ শুরু করি এবং স্থিতি প্রদর্শন করি (2)

এর পরে, আমরা আমাদের মূল থ্রেডটি 70 সেকেন্ডের জন্য বিরতি দিই, স্ট্যাটাসটি প্রিন্ট করি (3) , তারপর আবার 3টি টাস্ক যোগ করুন এবং আবার স্ট্যাটাসটি প্রিন্ট করুন (4)

যেখানে আমরা একটি টাস্ক যোগ করার সাথে সাথেই স্থিতি প্রদর্শন করি, সেখানে আমরা প্রথমে আপ-টু-ডেট আউটপুটের জন্য 1-সেকেন্ডের ঘুম যোগ করি।


ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 3; i++) {
            executorService.submit(new Task(i));
        }
 
        TimeUnit.SECONDS.sleep(1);
            System.out.println(executorService);	//(1)
 
        TimeUnit.SECONDS.sleep(30);
 
        executorService.submit(new Task(3));
        TimeUnit.SECONDS.sleep(1);
            System.out.println(executorService);	//(2)
 
        TimeUnit.SECONDS.sleep(70);
 
            System.out.println(executorService);	//(3)
 
        for (int i = 4; i < 7; i++) {
            executorService.submit(new Task(i));
        }
 
        TimeUnit.SECONDS.sleep(1);
            System.out.println(executorService);	//(4)
        executorService.shutdown();

এবং এখানে ফলাফল:

পুল-1-থ্রেড-1 থ্রেডে প্রক্রিয়াকৃত ব্যবহারকারীর অনুরোধ #0
পুল-1-থ্রেড-2 থ্রেডে
প্রক্রিয়াকৃত ব্যবহারকারী অনুরোধ #1 পুল-1-থ্রেড-3 থ্রেডে প্রক্রিয়াকৃত ব্যবহারকারীর অনুরোধ #
2 (1) java.util.concurrent .ThreadPoolExecutor@f6f4d33[চলমান, পুলের আকার = 3, সক্রিয় থ্রেডগুলি = 0, সারিবদ্ধ কাজগুলি = 0, সম্পন্ন করা কাজগুলি = 3] পুল-
1-থ্রেড-2 থ্রেড
(2) java.util.concurrent-এ প্রক্রিয়াকৃত ব্যবহারকারীর অনুরোধ #3। ThreadPoolExecutor@f6f4d33[চলমান, পুলের আকার = 3, সক্রিয় থ্রেডগুলি = 0, সারিবদ্ধ কাজগুলি = 0, সম্পন্ন করা কাজগুলি = 4] (3)
java.util.concurrent.ThreadPoolExecutor@f6f4d33[চলমান, পুলের আকার = 0, সক্রিয় পাঠ = 0 , সারিবদ্ধ কাজগুলি = 0, সম্পন্ন করা কাজগুলি = 4]
পুল-1-থ্রেড-4 থ্রেডে প্রক্রিয়াকৃত ব্যবহারকারীর অনুরোধ #4
পুল-1-থ্রেড-5 থ্রেডে প্রক্রিয়াকৃত ব্যবহারকারীর অনুরোধ #5
পুল-1-থ্রেড-4 থ্রেড
(4) java.util.concurrent.ThreadPoolExecutor@f6f4d33[চলমান, পুলের আকার = 2, সক্রিয় থ্রেড = 0, সারিবদ্ধ কাজগুলি = 0, সম্পন্ন করা কাজগুলি = 7]-এ প্রক্রিয়াকৃত ব্যবহারকারীর অনুরোধ #6

আসুন প্রতিটি ধাপে যাই:

ধাপ ব্যাখ্যা
1 (3টি কাজ সম্পন্ন করার পর) আমরা 3টি থ্রেড তৈরি করেছি এবং এই তিনটি থ্রেডে 3টি কাজ সম্পাদন করা হয়েছে।
স্ট্যাটাসটি প্রদর্শিত হলে, 3টি কাজ সম্পন্ন হয় এবং থ্রেডগুলি অন্যান্য কাজ সম্পাদন করার জন্য প্রস্তুত।
2 (30-সেকেন্ড বিরতির পরে এবং অন্য একটি কাজ সম্পাদন) 30 সেকেন্ডের নিষ্ক্রিয়তার পরে, থ্রেডগুলি এখনও জীবিত এবং কাজের জন্য অপেক্ষা করছে।
বাকি লাইভ থ্রেডগুলির পুল থেকে নেওয়া একটি থ্রেডে আরেকটি কাজ যোগ করা হয় এবং চালানো হয়।
পুলে কোনো নতুন থ্রেড যোগ করা হয়নি।
3 (70-সেকেন্ড বিরতির পরে) থ্রেড পুল থেকে সরানো হয়েছে.
কাজ গ্রহণ করার জন্য প্রস্তুত কোন থ্রেড নেই.
4 (আরো 3টি কাজ সম্পাদন করার পরে) আরও কাজ প্রাপ্ত হওয়ার পরে, নতুন থ্রেড তৈরি করা হয়েছিল। এবার মাত্র দুটি থ্রেড 3টি কাজ প্রক্রিয়া করতে পেরেছে।

ঠিক আছে, এখন আপনি অন্য ধরণের নির্বাহক পরিষেবার যুক্তির সাথে পরিচিত।

এক্সিকিউটর ইউটিলিটি ক্লাসের অন্যান্য পদ্ধতির সাথে সাদৃশ্য অনুসারে , নতুন ক্যাশেড থ্রেডপুল পদ্ধতিতে একটি ওভারলোডেড সংস্করণ রয়েছে যা একটি থ্রেডফ্যাক্টরি অবজেক্টকে একটি যুক্তি হিসাবে নেয়।