আমি একটি ইস্যুতে চলেছি যেখানে ThreadPoolExecutorপুলটি তৈরির পরে যদি আমি একটি পুলের পুলের আকারকে আলাদা একটি সংখ্যার সাথে পুনরায় আকার দেওয়ার চেষ্টা করি , তবে মাঝে মাঝে মাঝে কিছু কাজকে RejectedExecutionExceptionআমি প্রত্যাখ্যান করেও প্রত্যাখ্যান করা হয় যদিও আমি কখনও queueSize + maxPoolSizeসংখ্যার চেয়ে বেশি কাজ জমা দিই না ।
আমি যে সমস্যার সমাধান করতে চাইছি তা হ'ল ThreadPoolExecutorথ্রেড পুলের কাতারে বসে থাকা মুলতুবি মৃত্যুদণ্ডের ভিত্তিতে এর মূল থ্রেডগুলির আকার পরিবর্তন করে extend আমার এটি দরকার কারণ ডিফল্টরূপে ThreadPoolExecutorএকটি নতুন তৈরি করবে Threadকেবলমাত্র যদি সারি পূর্ণ হয়।
এখানে একটি ছোট স্ব-অন্তর্ভুক্ত বিশুদ্ধ জাভা 8 প্রোগ্রাম যা সমস্যাটি দেখায়।
import static java.lang.Math.max;
import static java.lang.Math.min;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolResizeTest {
public static void main(String[] args) throws Exception {
// increase the number of iterations if unable to reproduce
// for me 100 iterations have been enough
int numberOfExecutions = 100;
for (int i = 1; i <= numberOfExecutions; i++) {
executeOnce();
}
}
private static void executeOnce() throws Exception {
int minThreads = 1;
int maxThreads = 5;
int queueCapacity = 10;
ThreadPoolExecutor pool = new ThreadPoolExecutor(
minThreads, maxThreads,
0, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(queueCapacity),
new ThreadPoolExecutor.AbortPolicy()
);
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(() -> resizeThreadPool(pool, minThreads, maxThreads),
0, 10, TimeUnit.MILLISECONDS);
CompletableFuture<Void> taskBlocker = new CompletableFuture<>();
try {
int totalTasksToSubmit = queueCapacity + maxThreads;
for (int i = 1; i <= totalTasksToSubmit; i++) {
// following line sometimes throws a RejectedExecutionException
pool.submit(() -> {
// block the thread and prevent it from completing the task
taskBlocker.join();
});
// Thread.sleep(10); //enabling even a small sleep makes the problem go away
}
} finally {
taskBlocker.complete(null);
scheduler.shutdown();
pool.shutdown();
}
}
/**
* Resize the thread pool if the number of pending tasks are non-zero.
*/
private static void resizeThreadPool(ThreadPoolExecutor pool, int minThreads, int maxThreads) {
int pendingExecutions = pool.getQueue().size();
int approximateRunningExecutions = pool.getActiveCount();
/*
* New core thread count should be the sum of pending and currently executing tasks
* with an upper bound of maxThreads and a lower bound of minThreads.
*/
int newThreadCount = min(maxThreads, max(minThreads, pendingExecutions + approximateRunningExecutions));
pool.setCorePoolSize(newThreadCount);
pool.prestartAllCoreThreads();
}
}
যদি আমি কিউ-ক্যাপাসিটি + ম্যাক্সথ্রেডগুলি আরও কখনও জমা না করি তবে পুলটিকে কখনই প্রত্যাখাত এক্সেক্সিউশনএক্সেপশন নিক্ষেপ করা উচিত। থ্রেডপুলএক্সিকিউটারের সংজ্ঞা অনুসারে আমি কখনই সর্বোচ্চ থ্রেডগুলি পরিবর্তন করছি না, এটি হয় কোনও থ্রেডে বা কাতারে সামঞ্জস্য করা উচিত।
অবশ্যই, যদি আমি পুলটিকে কখনই আকার না দিয়ে থাকি তবে থ্রেড পুল কখনই কোনও জমা দেয় না। এটি ডিবাগ করাও শক্ত যেহেতু সাবমিশনে কোনও ধরণের বিলম্ব যুক্ত করা সমস্যাটিকে দূরে সরিয়ে দেয়।
প্রত্যাশিত এক্সেক্সিউশন এক্সপসেপশন কীভাবে ঠিক করবেন তার কোনও পয়েন্টার?
ThreadPoolExecutorকরা খুব সম্ভবত একটি খারাপ ধারণা, এবং আপনারও কি এই ক্ষেত্রে বিদ্যমান কোড পরিবর্তন করার দরকার নেই? আপনার আসল কোড কীভাবে নির্বাহককে অ্যাক্সেস করে তার কিছু উদাহরণ প্রদান করা ভাল। আমি যদি অবাক হয়ে থাকি যদি এটি নির্দিষ্টভাবে ThreadPoolExecutor(যেমন না হয় ExecutorService) নির্দিষ্ট পদ্ধতি ব্যবহার করে ।
ExecutorServiceকোনও বিদ্যমানকে মুড়ে ফেলে যা পুনরায় আকার দেওয়ার কারণে জমা দেওয়া কাজগুলিকে পুনরায় জমা দেয়?