নিম্নলিখিত শ্রেণিটি একটি থ্রেডপুলএক্সিকিউটারের চারপাশে মোড়ক করে এবং ব্লক করতে একটি সেমফোর ব্যবহার করে তারপরে কাজের সারিটি পূর্ণ:
public final class BlockingExecutor {
private final Executor executor;
private final Semaphore semaphore;
public BlockingExecutor(int queueSize, int corePoolSize, int maxPoolSize, int keepAliveTime, TimeUnit unit, ThreadFactory factory) {
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
this.executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, unit, queue, factory);
this.semaphore = new Semaphore(queueSize + maxPoolSize);
}
private void execImpl (final Runnable command) throws InterruptedException {
semaphore.acquire();
try {
executor.execute(new Runnable() {
@Override
public void run() {
try {
command.run();
} finally {
semaphore.release();
}
}
});
} catch (RejectedExecutionException e) {
// will never be thrown with an unbounded buffer (LinkedBlockingQueue)
semaphore.release();
throw e;
}
}
public void execute (Runnable command) throws InterruptedException {
execImpl(command);
}
}
এই মোড়কের ক্লাসটি ব্রায়ান গয়েটসের অনুশীলনে জাভা কনকুরન્સી বইয়ে দেওয়া সমাধানের ভিত্তিতে। বইয়ের সমাধানটিতে কেবল দুটি কনস্ট্রাক্টর প্যারামিটার লাগে: Executor
সেমফোরের জন্য একটি এবং একটি সীমা ব্যবহৃত। এটি ফিক্সপয়েন্টের দেওয়া উত্তরে দেখানো হয়েছে। এই পদ্ধতির সাথে একটি সমস্যা আছে: এটি এমন অবস্থায় যেতে পারে যেখানে পুলের থ্রেডগুলি ব্যস্ত থাকে, সারিটি পূর্ণ থাকে, তবে সেমফোর সবেমাত্র একটি অনুমতি প্রকাশ করেছে। (semaphore.release()
শেষ অবধি) এই রাজ্যে, একটি নতুন টাস্ক সবেমাত্র প্রকাশিত পারমিটটি দখল করতে পারে, তবে টাস্ক সারি পূর্ণ হওয়ায় তা প্রত্যাখ্যান করা হয়। অবশ্যই এটি আপনি চান এমন কিছু নয়; আপনি এই ক্ষেত্রে অবরুদ্ধ করতে চান।
এই সমস্যার সমাধানের উদ্দেশ্যে, আমরা একটি ব্যবহার করা আবশ্যক সীমাবদ্ধ যেমন JCiP পরিষ্কারভাবে উল্লেখ, কিউ। ভার্চুয়াল সারি আকারের প্রভাব প্রদান করে সেমফোর একটি প্রহরী হিসাবে কাজ করে। এর পার্শ্ব প্রতিক্রিয়া রয়েছে যে ইউনিটটি maxPoolSize + virtualQueueSize + maxPoolSize
কার্যগুলি থাকতে পারে এটি সম্ভব । তা কেন? কারণ
semaphore.release()
শেষ অবধি। যদি সমস্ত পুল থ্রেড একই সময়ে এই বিবৃতিতে কল করে, তবে maxPoolSize
একই সংখ্যার কাজগুলিকে ইউনিটে প্রবেশের অনুমতি দিয়ে অনুমতিগুলি মুক্তি দেওয়া হয়। যদি আমরা একটি সীমাবদ্ধ সারি ব্যবহার করতাম তবে এটি পুরোপুরি পূর্ণ হবে, ফলস্বরূপ প্রত্যাখ্যানিত কোনও কার্য। এখন, কারণ আমরা জানি যে এটি কেবল তখনই ঘটে যখন পুলের থ্রেডটি প্রায় শেষ হয়ে যায়, এটি কোনও সমস্যা নয়। আমরা জানি যে পুলের থ্রেডটি ব্লক করবে না, সুতরাং শীঘ্রই একটি কাজ নেওয়া হবে।
আপনি যদিও সীমাবদ্ধ সারি ব্যবহার করতে সক্ষম হন। এটির আকার সমান হয় তা নিশ্চিত করুন virtualQueueSize + maxPoolSize
। বৃহত্তর আকারগুলি অকেজো, সেম্যাফোর আরও আইটেমগুলিতে প্রবেশ করতে বাধা দেবে mal আকার হ্রাস হওয়ায় কাজের প্রত্যাখাত হওয়ার সুযোগ বাড়ে। উদাহরণস্বরূপ, বলুন আপনি সর্বাধিকপুলসাইজ = 2 এবং ভার্চুয়ালকিউসাইজ = 5 সহ একটি সীমাবদ্ধ নির্বাহক চান। তারপরে 5 + 2 = 7 পারমিট এবং 5 + 2 = 7 এর আসল কাতারের আকারের সাথে একটি সেমফোর নিন। ইউনিটে থাকা কার্যগুলির প্রকৃত সংখ্যাটি হ'ল 2 + 5 + 2 = 9। যখন নির্বাহক পূর্ণ হয়ে থাকে (সারিতে 5 টি কাজ, থ্রেড পুলে 2, সুতরাং 0 পারমিট উপলব্ধ থাকে) এবং সমস্ত পুল থ্রেডগুলি তাদের পারমিট প্রকাশ করে, ঠিক তখনই 2 টি অনুমতি নিয়ে আসা কার্যগুলি গ্রহণ করা যেতে পারে।
এখন জেসিপি থেকে সমাধানটি ব্যবহার করা কিছুটা জটিল as কারণ এটি এই সমস্ত সীমাবদ্ধতাগুলি নিষ্ক্রিয় করে না (আনবাউন্ডেড সারি, বা ma গণিতের বিধিনিষেধ ইত্যাদি)। আমি মনে করি যে এটি ইতিমধ্যে উপলব্ধ অংশগুলির উপর ভিত্তি করে আপনি কীভাবে নতুন থ্রেড নিরাপদ শ্রেণি তৈরি করতে পারেন তা প্রমাণ করার জন্য এটি কেবলমাত্র একটি ভাল উদাহরণ হিসাবে কাজ করে তবে একটি পূর্ণ বয়স্ক, পুনরায় ব্যবহারযোগ্য শ্রেণি হিসাবে নয়। আমি মনে করি না যে পরবর্তীকটি লেখকের উদ্দেশ্য ছিল।