newCachedThreadPool()
বনাম newFixedThreadPool()
আমি কখন এক বা অন্যটি ব্যবহার করব? সম্পদ ব্যবহারের ক্ষেত্রে কোন কৌশলটি আরও ভাল?
newCachedThreadPool()
বনাম newFixedThreadPool()
আমি কখন এক বা অন্যটি ব্যবহার করব? সম্পদ ব্যবহারের ক্ষেত্রে কোন কৌশলটি আরও ভাল?
উত্তর:
আমার মনে হয় ডকসগুলি এই দুটি ফাংশনের পার্থক্য এবং ব্যবহারকে বেশ ভালভাবে ব্যাখ্যা করেছে:
একটি থ্রেড পুল তৈরি করে যা একটি ভাগ করা আনবাউন্ডেড কাতারে অপারেটিং করে স্থির সংখ্যক থ্রেডকে পুনরায় ব্যবহার করে। যে কোনও সময়ে, সর্বাধিক এন থ্রেড থ্রেড সক্রিয় প্রক্রিয়াজাতকরণ কাজ হবে be সমস্ত থ্রেড সক্রিয় থাকাকালীন অতিরিক্ত কাজগুলি যদি জমা দেওয়া হয় তবে কোনও থ্রেড পাওয়া না পাওয়া পর্যন্ত তারা সারিতে অপেক্ষা করবে। শাটডাউন করার আগে এক্সিকিউশন চলাকালীন ব্যর্থতার কারণে যদি কোনও থ্রেড বন্ধ হয়ে যায়, পরবর্তী কাজগুলি সম্পাদন করার জন্য প্রয়োজনে একটি নতুন স্থানটি গ্রহণ করবে। পুলটিতে থ্রেডগুলি উপস্থিত থাকবে যতক্ষণ না এটি স্পষ্টভাবে বন্ধ হয়ে যায়।
একটি থ্রেড পুল তৈরি করে যা প্রয়োজন অনুসারে নতুন থ্রেড তৈরি করে তবে পূর্বে নির্মিত থ্রেডগুলি উপলব্ধ হলে তা পুনরায় ব্যবহার করবে। এই পুলগুলি সাধারণত অনেক স্বল্পমেয়াদী অ্যাসিনক্রোনাস কার্য সম্পাদন করে এমন প্রোগ্রামগুলির কার্যকারিতা উন্নত করে। কার্যকর করার জন্য কলগুলি উপলব্ধ থাকলে পূর্বে নির্মিত থ্রেডগুলি পুনরায় ব্যবহার করবে। যদি বিদ্যমান থ্রেড না পাওয়া যায় তবে একটি নতুন থ্রেড তৈরি করা হবে এবং পুলটিতে যুক্ত হবে। ষাট সেকেন্ডের জন্য ব্যবহৃত হয়নি এমন থ্রেডগুলি সমাপ্ত এবং ক্যাশে থেকে সরানো হয়। সুতরাং, একটি পুল যা দীর্ঘকাল ধরে অলস থাকে সেগুলি কোনও সংস্থান গ্রহণ করবে না। নোট করুন যে অনুরূপ বৈশিষ্ট্যযুক্ত পুলগুলি কিন্তু বিভিন্ন বিবরণ (উদাহরণস্বরূপ, টাইমআউট পরামিতি) থ্রেডপুলএক্সেক্টর কনস্ট্রাক্টর ব্যবহার করে তৈরি করা যেতে পারে।
সংস্থানগুলির ক্ষেত্রে, newFixedThreadPool
সমস্ত থ্রেডগুলি স্পষ্টভাবে শেষ না হওয়া অবধি চলমান রাখে। ইন newCachedThreadPool
টপিক যে ষাট সেকেন্ডের জন্য ব্যবহার করা হয়েছে সমাপ্ত এবং ক্যাশ থেকে সরিয়ে ফেলা হয়।
এটি দেওয়া, রিসোর্স খরচ পরিস্থিতি খুব নির্ভর করবে। উদাহরণস্বরূপ, আপনার যদি দীর্ঘ প্রচুর কাজ চালানো হয় তবে আমি এটির পরামর্শ দেব suggestFixedThreadPool
। CachedThreadPool
ডকস হিসাবে , "এই পুলগুলি সাধারণত অনেক স্বল্পমেয়াদী অ্যাসিনক্রোনাস কার্য সম্পাদন করে এমন প্রোগ্রামগুলির কার্য সম্পাদনকে উন্নত করবে" say
newCachedThreadPool
সম্ভবত কিছু গুরুতর সমস্যার কারণ হতে পারে কারণ আপনি সমস্ত নিয়ন্ত্রণ ছেড়ে চলে যান thread pool
এবং যখন পরিষেবা একই হোস্টে অন্যদের সাথে কাজ করে যা দীর্ঘসময় সিপিইউয়ের অপেক্ষার কারণে অন্যদের ক্রাশের কারণ হতে পারে। সুতরাং আমি মনে করি newFixedThreadPool
এই ধরণের দৃশ্যে আরও সুরক্ষিত হতে পারে। এছাড়াও এই পোস্টটি তাদের মধ্যে সর্বাধিক অসামান্য পার্থক্য স্পষ্ট করে।
কেবলমাত্র অন্য উত্তরগুলি সম্পূর্ণ করতে, আমি জোশুয়া ব্লচ, অধ্যায় 10, আইটেম 68 এর কার্যকর জাভা, দ্বিতীয় সংস্করণটি উদ্ধৃত করতে চাই:
"একটি বিশেষ অ্যাপ্লিকেশনের জন্য নির্বাহক সেবা নির্বাচন চতুর হতে পারে। আপনি যদি একটি লেখার তাহলে ছোট প্রোগ্রাম একটি অথবা স্বল্প লোড সার্ভার ব্যবহার Executors.new- CachedThreadPool হয় সাধারণত একটি ভাল পছন্দ , যেমন এটি কোন কনফিগারেশন দাবী এবং সাধারণত" করে ঠীক জিনিস." তবে প্রচুর পরিমাণে বোঝা উত্পাদনের সার্ভারের জন্য ক্যাশেড থ্রেড পুলটি ভাল পছন্দ নয় !
একটি ক্যাশেড থ্রেড পুলে , জমা দেওয়া কাজগুলি সারিবদ্ধ না করে অবিলম্বে মৃত্যুদন্ড কার্যকর করার জন্য একটি থ্রেডের কাছে হস্তান্তর করা হয়। যদি কোনও থ্রেড উপলব্ধ না থাকে তবে একটি নতুন তৈরি করা হয় । যদি কোনও সার্ভার এত বেশি বোঝা হয়ে থাকে যে এর সমস্ত সিপিইউ সম্পূর্ণরূপে ব্যবহার করা হয় এবং আরও কাজ উপস্থিত হয়, আরও থ্রেড তৈরি করা হবে, যা কেবল বিষয়টিকে আরও খারাপ করে দেবে।
অতএব, ভারী বোঝাই হওয়া প্রোডাকশন সার্ভারে আপনি এক্সিকিউটার্স.নেউফিক্সডথ্রেডপুল ব্যবহার করে অনেক বেশি ভাল , যা আপনাকে সর্বোচ্চ নিয়ন্ত্রণের জন্য একটি নির্দিষ্ট সংখ্যক থ্রেড সহ একটি পুল সরবরাহ করে বা সরাসরি থ্রেডপুলএক্সেসিটার শ্রেণি ব্যবহার করে । "
আপনি যদি সোর্স কোডটি দেখে থাকেন তবে দেখতে পাবেন তারা থ্রেডপুলএক্সেকিউটারকে কল করছে। অভ্যন্তরীণভাবে এবং তাদের সম্পত্তি নির্ধারণ। আপনার প্রয়োজনের আরও ভাল নিয়ন্ত্রণ রাখতে আপনি এটি তৈরি করতে পারেন।
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
যদি আপনি কলযোগ্য / চলমান কার্যগুলির সীমাহীন সারি সম্পর্কে উদ্বিগ্ন না হন তবে আপনি সেগুলির একটি ব্যবহার করতে পারেন। ব্রুনো দ্বারা প্রস্তাবিত হিসাবে, আমি খুব পছন্দ newFixedThreadPool
করতে newCachedThreadPool
এই দুটি করে।
তবে থ্রেডপুলএ্যাক্সিকিউটর হয় newFixedThreadPool
বা এর তুলনায় আরও নমনীয় বৈশিষ্ট্য সরবরাহ করেnewCachedThreadPool
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)
সুবিধাদি:
আপনার ব্লকিংকিউ আকারের সম্পূর্ণ নিয়ন্ত্রণ রয়েছে । এটি পূর্ববর্তী দুটি বিকল্পের বিপরীতে, সীমাহীন নয়। সিস্টেমে যখন অপ্রত্যাশিত অশান্তি দেখা দেয় তখন মুলতুবি কলযোগ্য / চলমান কাজগুলির বিশাল পাইল-আপের কারণে আমি মেমরির ত্রুটি থেকে বেরিয়ে যাব না।
আপনি কাস্টম প্রত্যাখ্যান হ্যান্ডলিং নীতি বাস্তবায়ন করতে পারেন বা নীতিগুলির মধ্যে একটি ব্যবহার করতে পারেন:
ডিফল্টরূপে ThreadPoolExecutor.AbortPolicy
, হ্যান্ডলার প্রত্যাখ্যানের পরে একটি রানটাইম রিজেক্টেড এক্সেক্সিউশন এক্সেপশন নিক্ষেপ করে।
ইন ThreadPoolExecutor.CallerRunsPolicy
, যে থ্রেডটি সম্পাদন করে তা নিজেই চালায় itself এটি একটি সাধারণ প্রতিক্রিয়া নিয়ন্ত্রণ ব্যবস্থা সরবরাহ করে যা নতুন কার্য জমা দেওয়ার হারকে ধীর করে দেয়।
ইন ThreadPoolExecutor.DiscardPolicy
, একটি কার্য যা কার্যকর করা যায় না তা কেবল বাদ দেওয়া হয়।
ইন ThreadPoolExecutor.DiscardOldestPolicy
, এক্সিকিউটারটি যদি বন্ধ না করা হয় তবে কাজের সারির শীর্ষে থাকা কাজটি ফেলে দেওয়া হয় এবং তারপরে মৃত্যুদন্ড কার্যকর করার চেষ্টা করা হয় (যা আবার ব্যর্থ হতে পারে, যার ফলে এটি পুনরাবৃত্তি হতে পারে))
আপনি নীচের ব্যবহারের ক্ষেত্রে একটি কাস্টম থ্রেড কারখানা বাস্তবায়ন করতে পারেন:
এটা ঠিক, Executors.newCachedThreadPool()
একাধিক ক্লায়েন্ট এবং একযোগে অনুরোধগুলির পরিবেশন করা সার্ভার কোডের জন্য দুর্দান্ত পছন্দ নয়।
কেন? এটির সাথে মূলত দুটি (সম্পর্কিত) সমস্যা রয়েছে:
এটি সীমাহীন, যার অর্থ আপনি কেবলমাত্র পরিষেবাতে আরও কাজ ইনজেকশনের মাধ্যমে আপনার জেভিএমকে পঙ্গু করার জন্য দ্বার উন্মুক্ত করছেন (ডস আক্রমণ)। থ্রেডগুলি অ-অবহেলিত পরিমাণ মেমরি গ্রাস করে এবং তাদের কার্য-অগ্রগতির ভিত্তিতে মেমরির খরচও বাড়ায়, সুতরাং কোনও সার্ভারকে এইভাবে টপ্পল করা সহজ (যদি আপনার জায়গায় অন্য সার্কিট-ব্রেকার না থাকে)।
আনবাউন্ডেড সমস্যাটি আরও বাড়িয়ে দিয়েছে যে নির্বাহক একটি ফ্রন্টেন্ট করেছেন SynchronousQueue
যার অর্থ টাস্ক প্রদানকারী এবং থ্রেড পুলের মধ্যে সরাসরি হ্যান্ডঅফ রয়েছে। প্রতিটি বিদ্যমান টাস্ক যদি সমস্ত বিদ্যমান থ্রেডে ব্যস্ত থাকে তবে একটি নতুন থ্রেড তৈরি করবে। এটি সার্ভার কোডের জন্য সাধারণত খারাপ কৌশল। সিপিইউ যখন স্যাচুরেটেড হয়ে যায়, বিদ্যমান কাজগুলি শেষ হতে আরও বেশি সময় নেয়। তবুও আরও কাজ জমা দেওয়া হচ্ছে এবং আরও থ্রেড তৈরি করা হয়েছে, সুতরাং কাজগুলি সম্পূর্ণ হতে আরও বেশি সময় নেয়। সিপিইউ যখন স্যাচুরেটেড হয়, তখন আরও থ্রেডগুলি অবশ্যই সার্ভারের প্রয়োজন মতো হয় না।
এখানে আমার প্রস্তাবনাগুলি:
একটি স্থির আকারের থ্রেড পুল এক্সিকিউটরস.নিউফিক্সডথ্রেডপুল বা একটি থ্রেডপুলএক্সেকিউটার ব্যবহার করুন। একটি সেট সর্বাধিক সংখ্যক থ্রেড সহ;
ThreadPoolExecutor
বর্গ নির্বাহক যে অনেক থেকে প্রত্যাগত হয় জন্য বেস বাস্তবায়ন Executors
কারখানা পদ্ধতি। সুতরাং আসুন এর দৃষ্টিকোণ থেকে স্থির এবং ক্যাশেড থ্রেড পুলের কাছে যাওয়া যাক ThreadPoolExecutor
।
প্রধান কন্সট্রাকটর এই শ্রেণীর এই মত দেখায়:
public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler
)
corePoolSize
লক্ষ্য থ্রেড পুল নূন্যতম আকারের নির্ধারণ করে। কার্যকর করার কোনও কাজ না থাকলেও বাস্তবায়ন সেই আকারের একটি পুল বজায় রাখে।
এটি maximumPoolSize
হ'ল সর্বোচ্চ সংখ্যক থ্রেড যা একবারে সক্রিয় হতে পারে।
থ্রেড পুলটি বড় হওয়ার পরে এবং corePoolSize
প্রান্তিকের চেয়ে বড় হওয়ার পরে , নির্বাহক নিষ্ক্রিয় থ্রেডগুলি শেষ করে corePoolSize
আবারও পৌঁছাতে পারে । যদি allowCoreThreadTimeOut
সত্য হয় তবে নির্বাহক এমনকি কোর পুলের থ্রেডগুলি বন্ধ করতে পারেন যদি তারা keepAliveTime
প্রান্তিকের চেয়ে বেশি অলস থাকে ।
সুতরাং নীচের অংশটি হ'ল keepAliveTime
থ্রেডহোল্ডের চেয়ে থ্রেডগুলি যদি অলস থাকে , তবে তাদের কোনও চাহিদা নেই বলে সেগুলি বন্ধ হয়ে যেতে পারে।
নতুন কোন টাস্ক আসার সাথে সাথে সমস্ত মূল থ্রেড দখল হয়ে গেলে কী ঘটে? নতুন কার্যগুলি সেই BlockingQueue<Runnable>
উদাহরণের মধ্যে সারি করা হবে । যখন কোনও থ্রেড নিখরচায় পরিণত হয়, তখন এই সারিবদ্ধ কাজগুলির মধ্যে একটিতে প্রক্রিয়া করা যায়।
BlockingQueue
জাভাতে ইন্টারফেসের বিভিন্ন বাস্তবায়ন রয়েছে , তাই আমরা বিভিন্ন সারি পদ্ধতি যেমন প্রয়োগ করতে পারি:
সীমাবদ্ধ সারি : নতুন কার্যগুলি একটি সীমাবদ্ধ টাস্ক সারির মধ্যে সারি করা হবে।
আনবাউন্ডেড সারি : আনবাউন্ডেড টাস্কের সারিটির মধ্যে নতুন কার্যগুলি সারিবদ্ধ করা হবে। সুতরাং এই সারিটি হ্যাপের আকারটি যতটা অনুমতি দেয় তত বাড়তে পারে।
সিঙ্ক্রোনাস হ্যান্ডঅফ : আমরা SynchronousQueue
নতুন কার্যগুলি সারি করার জন্যও ব্যবহার করতে পারি । সেক্ষেত্রে কোনও নতুন কার্য সারিবদ্ধ করার সময়, অন্য থ্রেডটি ইতিমধ্যে সেই কাজের জন্য অপেক্ষা করতে হবে।
কীভাবে ThreadPoolExecutor
একটি নতুন কার্য সম্পাদন করে তা এখানে :
corePoolSize
থ্রেডের চেয়ে কম চলমান থাকলে প্রদত্ত টাস্কটিকে প্রথম কাজ হিসাবে একটি নতুন থ্রেড শুরু করার চেষ্টা করে।BlockingQueue#offer
পদ্ধতিটি ব্যবহার করে নতুন কাজটি সজ্জিত করার চেষ্টা করে
। offer
যদি কিউ পরিপূর্ণ এবং অবিলম্বে ফেরৎ পদ্ধতি ব্লক করা হবে না false
।offer
প্রত্যাবর্তন false
) সারি করতে ব্যর্থ হয় , তবে এটি থ্রেড পুলে এটির প্রথম কাজ হিসাবে একটি নতুন থ্রেড যুক্ত করার চেষ্টা করে।RejectedExecutionHandler
।স্থির এবং ক্যাশেড থ্রেড পুলগুলির মধ্যে প্রধান পার্থক্য এই তিনটি কারণের মধ্যে ফোটে:
+ + ----------- + + ----------- + + ------------------- + + ----- ---------------------------- + + | পুলের ধরন | কোর আকার | সর্বোচ্চ আকার | কুইউং কৌশল | + + ----------- + + ----------- + + ------------------- + + ----- ---------------------------- + + | স্থির | n (স্থির) | n (স্থির) | আনবাউন্ডেড `লিংকডব্লকিংকুইউ | + + ----------- + + ----------- + + ------------------- + + ----- ---------------------------- + + | ক্যাশেড | 0 | পূর্ণসংখ্যা। MAX_VALUE | `সিঙ্ক্রোনাস কিউইউ | + + ----------- + + ----------- + + ------------------- + + ----- ---------------------------- + +
Excutors.newFixedThreadPool(n)
কাজ করে তা এখানে :
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
আপনি দেখতে পারেন:
OutOfMemoryError
।আমি কখন এক বা অন্যটি ব্যবহার করব? সম্পদ ব্যবহারের ক্ষেত্রে কোন কৌশলটি আরও ভাল?
আমরা যখন রিসোর্স ম্যানেজমেন্টের উদ্দেশ্যে একসাথে কাজগুলি সীমাবদ্ধ করতে যাচ্ছি তখন একটি নির্দিষ্ট আকারের থ্রেড পুলটি ভাল প্রার্থী বলে মনে হয় ।
উদাহরণস্বরূপ, যদি আমরা ওয়েব সার্ভারের অনুরোধগুলি পরিচালনা করতে কোনও নির্বাহককে ব্যবহার করতে যাচ্ছি তবে একটি নির্দিষ্ট নির্বাহক অনুরোধটি আরও যুক্তিসঙ্গতভাবে হ্যান্ডেল করতে পারে।
আরও উন্নত সংস্থান ব্যবস্থাপনার জন্য, যুক্তিসঙ্গত সাথে মিলিত ThreadPoolExecutor
একটি সীমাবদ্ধ BlockingQueue<T>
বাস্তবায়ন সহ একটি কাস্টম তৈরি করার পক্ষে এটি সুপারিশ করা হয় RejectedExecutionHandler
।
কীভাবে Executors.newCachedThreadPool()
কাজ করে তা এখানে :
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
আপনি দেখতে পারেন:
Integer.MAX_VALUE
। ব্যবহারিকভাবে, থ্রেড পুল আনবাউন্ডেড।SynchronousQueue
যখন অন্য প্রান্তে কেউ না থাকায় সর্বদা একটি নতুন কাজ দেওয়া ব্যর্থ হয়!আমি কখন এক বা অন্যটি ব্যবহার করব? সম্পদ ব্যবহারের ক্ষেত্রে কোন কৌশলটি আরও ভাল?
আপনার যখন ভবিষ্যদ্বাণীযোগ্য স্বল্প-চলমান কাজগুলি করেন তখন এটি ব্যবহার করুন।
জাভাডোক-তে বর্ণিত স্বল্প-কালীন অ্যাসিনক্রোনাস কাজগুলি কেবল তখনই আপনাকে নিউক্যাশডথ্রেডপুল ব্যবহার করতে হবে, আপনি যদি প্রক্রিয়াটি করতে বেশি সময় নেয় এমন কাজগুলি জমা দেন তবে আপনি অনেকগুলি থ্রেড তৈরি করবেন। আপনি দ্রুত নতুন হারে চালিত টাস্কগুলিকে নতুন ক্যাশেডথ্রেডপুল ( http://rashcoder.com/be-careful- while- using-executors-newcachedthreadpool/ ) এ দ্রুততম হারে দাখিল করলে আপনি 100% সিপিইউতে আঘাত করতে পারেন ।
আমি কিছু দ্রুত পরীক্ষা করি এবং নিম্নলিখিত ফলাফলগুলি পেয়েছি:
1) সিঙ্ক্রোনাসকিউ ব্যবহার করা হলে:
থ্রেডগুলি সর্বোচ্চ আকারে পৌঁছানোর পরে, নীচের মতো কোনও নতুন কাজ বাদ দেওয়া হবে।
থ্রেড "মূল" java.util.concurrent.RejectedExecutionException: কার্য java.util.concurrent.FutureTask@3fi733d java.util.concurrent.ThreadPoolExecutor@5acf9800 থেকে প্রত্যাখ্যান [চলমান, পুলের আকার = 3, সজ্জিত কার্য = 0, সম্পন্ন কাজগুলি = 0]
java.util.concurrent.ThreadPoolExecutor $ AbortPolicy.rejectedExecution (ThreadPoolExecutor.java:2047) এ
2) যদি লিঙ্কডব্লকিংকুই ব্যবহার করে:
থ্রেডগুলি সর্বনিম্ন আকার থেকে সর্বোচ্চ আকারে কখনই বৃদ্ধি পায় না, যার অর্থ থ্রেড পুলটি সর্বনিম্ন আকার হিসাবে স্থির আকার।