newFixedThreadPool metodi Executors sinfi bizga fixlangan miqdorda threadlar bilan executorService yaratadi. newSingleThreadExecutor metodiga qaraganda, biz poolda nechta thread ko'rishni istayotganimizni belgilaymiz. Taglikda chaqiriladi
new ThreadPoolExecutor( nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue
());
Parametrlar sifatida corePoolSize (qanday miqdorda threadlar tayyor bo'ladi (ishlatiladi) executor servis ishga tushirilganda) va maximumPoolSize (eng ko'p miqdorda threadlar, executor servis yaratishi mumkin) bir xil raqamni - newFixedThreadPool(nThreads) ichiga kiritilgan miqdorni yuboramiz. Xuddi shunday biz parametrlar ichiga o'zimizning ThreadFactory implementatsiyamizni ham yuborishimiz mumkin.
Xo'sh, nima uchun bizga bunday ExecutorService kerakligini tushunib olaylik.
Fixlangan miqdordagi (n) threadlar bilan ExecutorService quyidagi mantiqqa ega:
- Maksimum n threadlar tasklarni qayta ishlash uchun faol bo'ladi.
- Agar n dan ko'p task berilsa, ular navbatda turadi va threadlar bo'shaganida ishlanadi.
- Agar biron-bir thread ishlashda muvaffaqiyatsizlikka uchrasa va tugasa, buzilgan thread o'rniga yangi thread yaratiladi.
- Har qanday pooldan thread, pool yopilmaguncha faol bo'ladi.
Masalan, aeroportdagi navbatni tasavvur qiling, hamma bir navbatda turadi, lekin nazoratga yaqinlashganida mavjud bo'lgan punktlarga bo'linadi. Agar biror punktda kechikish yuz bersa, navbat faqat ikkinchi punkt orqali o'tadi birinchisi bo'shgunga qadar, va agar biror punkt butunlay ishdan chiqsa, shu punkt o'rniga yangi punkt ochiladi va nazorat ikki punkt orqali davom etadi.
Darhol aytish kerakki, sharoitlar ideal bo'lsa-da, va'da qilingan n threadlar barqaror ishlaydi va xato bilan tugagan threadlar uchun har doim zaxira bo'ladi (bu real aeroport ishi tufayli cheklangan resurslar tufayli mumkin emas), tizim bir nechta noxush xususiyatlarga ega, chunki hech qanday sharoitda threadlar ko'paymaydi, hatto navbat threadlardan tez o'sayotganida ham xuquqiy sharoitda tasklarni qayta ishlashda bo'lsa ham.
Amaliyotda ExecutorService fixlangan miqdordagi threadlar bilan qanday ishlashini o'rganishni taklif qilaman. Runnable implementatsiya qiluvchi sinf yarataylik. Bu sinfning ob'ektlari ExecutorService uchun tasklarimiz bo'ladi.
public class Task implements Runnable {
int taskNumber;
public Task(int taskNumber) {
this.taskNumber = taskNumber;
}
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Foydalanuvchi №" + taskNumber + " talabi " + Thread.currentThread().getName() + " threadida ishlov berildi");
}
}
run() metodida biz 2 soniya davomida threadni bloklaymiz, yuklama imitatsiya qilamiz va joriy task raqami va ushbu taskni bajarayotgan threadning nomini ekranga chiqaramiz.
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 30; i++) {
executorService.execute(new Task(i));
}
executorService.shutdown();
Avval main ichida ExecutorService yaratamiz va 30 ta taskni bajarishga yuboramiz.
Foydalanuvchi №0 talabi pool-1-thread-1 threadida ishlov berildi
Foydalanuvchi №2 talabi pool-1-thread-3 threadida ishlov berildi
Foydalanuvchi №5 talabi pool-1-thread-3 threadida ishlov berildi
Foydalanuvchi №3 talabi pool-1-thread-2 threadida ishlov berildi
Foydalanuvchi №4 talabi pool-1-thread-1 threadida ishlov berildi
Foydalanuvchi №8 talabi pool-1-thread-1 threadida ishlov berildi
Foydalanuvchi №6 talabi pool-1-thread-3 threadida ishlov berildi
Foydalanuvchi №7 talabi pool-1-thread-2 threadida ishlov berildi
Foydalanuvchi №10 talabi pool-1-thread-3 threadida ishlov berildi
Foydalanuvchi №9 talabi pool-1-thread-1 threadida ishlov berildi
Foydalanuvchi №11 talabi pool-1-thread-2 threadida ishlov berildi
Foydalanuvchi №12 talabi pool-1-thread-3 threadida ishlov berildi
Foydalanuvchi №14 talabi pool-1-thread-2 threadida ishlov berildi
Foydalanuvchi №13 talabi pool-1-thread-1 threadida ishlov berildi
Foydalanuvchi №15 talabi pool-1-thread-3 threadida ishlov berildi
Foydalanuvchi №16 talabi pool-1-thread-2 threadida ishlov berildi
Foydalanuvchi №17 talabi pool-1-thread-1 threadida ishlov berildi
Foydalanuvchi №18 talabi pool-1-thread-3 threadida ishlov berildi
Foydalanuvchi №19 talabi pool-1-thread-2 threadida ishlov berildi
Foydalanuvchi №20 talabi pool-1-thread-1 threadida ishlov berildi
Foydalanuvchi №21 talabi pool-1-thread-3 threadida ishlov berildi
Foydalanuvchi №22 talabi pool-1-thread-2 threadida ishlov berildi
Foydalanuvchi №23 talabi pool-1-thread-1 threadida ishlov berildi
Foydalanuvchi №25 talabi pool-1-thread-2 threadida ishlov berildi
Foydalanuvchi №24 talabi pool-1-thread-3 threadida ishlov berildi
Foydalanuvchi №26 talabi pool-1-thread-1 threadida ishlov berildi
Foydalanuvchi №27 talabi pool-1-thread-2 threadida ishlov berildi
Foydalanuvchi №28 talabi pool-1-thread-3 threadida ishlov berildi
Foydalanuvchi №29 talabi pool-1-thread-1 threadida ishlov berildi
Konsolda, tasklar qanday qilib turli threadlar bo'shagani sayin ishlatilishini ko'rib turibmiz.
Endi biz tasklar sonini 100 ga oshiramiz va 100 taskni bajarishga yuborishdan keyin, awaitTermination(11, SECONDS) metodini chaqiramiz. Parametrlarga miqdor va vaqt birligini yuboramiz. Ushbu metod asosiy threadni 11 soniya davomida to'sib qo'yadi, shundan keyin shutdownNow() ni chaqiramiz va barcha tasklar bajarilishini kuttirmay ExecutorService ni to'xtatamiz.
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 100; i++) {
executorService.execute(new Task(i));
}
executorService.awaitTermination(11, SECONDS);
executorService.shutdownNow();
System.out.println(executorService);
Oxirida executorService holati bo'yicha ma'lumotlarni ekranga chiqaramiz.
Konsolda quyidagi natijani ko'ramiz:
Foydalanuvchi №2 talabi pool-1-thread-3 threadida ishlov berildi
Foydalanuvchi №1 talabi pool-1-thread-2 threadida ishlov berildi
Foydalanuvchi №4 talabi pool-1-thread-3 threadida ishlov berildi
Foydalanuvchi №5 talabi pool-1-thread-2 threadida ishlov berildi
Foydalanuvchi №3 talabi pool-1-thread-1 threadida ishlov berildi
Foydalanuvchi №6 talabi pool-1-thread-3 threadida ishlov berildi
Foydalanuvchi №7 talabi pool-1-thread-2 threadida ishlov berildi
Foydalanuvchi №8 talabi pool-1-thread-1 threadida ishlov berildi
Foydalanuvchi №9 talabi pool-1-thread-3 threadida ishlov berildi
Foydalanuvchi №11 talabi pool-1-thread-1 threadida ishlov berildi
Foydalanuvchi №10 talabi pool-1-thread-2 threadida ishlov berildi
Foydalanuvchi №13 talabi pool-1-thread-1 threadida ishlov berildi
Foydalanuvchi №14 talabi pool-1-thread-2 threadida ishlov berildi
Foydalanuvchi №12 talabi pool-1-thread-3 threadida ishlov berildi
java.util.concurrent.ThreadPoolExecutor@452b3a41[Shutting down, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 15]
Foydalanuvchi №17 talabi pool-1-thread-3 threadida ishlov berildi
Foydalanuvchi №15 talabi pool-1-thread-1 threadida ishlov berildi
Foydalanuvchi №16 talabi pool-1-thread-2 threadida ishlov berildi
Keyingi uchta InterruptedException ni, bu 3 active tasklarning sleep metodlari chiqaradi.
Ko'rib turibmizki, tugatish vaqtida bizda 15 ta task bajarildi, lekin poolda hali ham 3 faol thread bor, ular taskni bajarishni tugatmadi. Bu 3 ta threadlarda interrupt() chaqiriladi, bu esa taskning bajarilishi tugaydi, lekin bizning holatimizda sleep metod bizga InterruptedExceptionni chiqaradi. Bundan tashqari, shutdownNow() metodini chaqirgandan so'ng tasklar qatori tozalanganligini ko'ramiz.
Shunday qilib, ExecutorService ni fixlangan miqdordagi threadlar bilan ishlatishda ish prinsipini hisobga olish kerak. Ushbu turdagi tasklar uchun ma'lum oldindan belgilangan barqaror yuklamalarga ega bo'lgan holatlarda foydalanishni tavsiya etiladi.
Yana bir qiziqarli savol: agar bir threadni ishlata oladigan executor kerak bo'lsa, qaysi metodni chaqirish kerak — newSingleThreadExecutor() yoki newFixedThreadPool(1)?
Har ikkala executor harakatda teng bo'ladi. Faqatgina farq shundaki, newSingleThreadExecutor() metodi bizga qaytaradigan executor, keyinchalik qo'shimcha streamlarni ishlatishga qayta sozlanmasdan bo'lib qoladi.
GO TO FULL VERSION