1 ta oqimlik ExecutorService nima uchun kerak bo'lishi mumkin?
Executors.newSingleThreadExecutor metodi orqali faqat bitta oqimlik ExecutorService yaratishimiz mumkin. Bu poolning ishlash logikasi quyidagicha:
- Xizmat bir vaqtning o'zida faqat bitta vazifani bajaradi.
- Agar biz N ta vazifani yuborsak, barcha N ta vazifalar ketma-ket bitta oqim orqali bajariladi.
- Agar oqim to'xtatilsa, qolgan vazifalarni bajarish uchun yangi oqim yaratiladi.
Bizning dasturimiz quyidagi funksionalni talab qilayotgan vaziyatni tasavvur qilaylik:
Bizga 30 soniya davomida foydalanuvchilardan kelayotgan so'rovlarni qayta ishlash kerak, ammo bir vaqtning o'zida faqat bitta so'rovni.
Foydalanuvchi so'rovini qayta ishlash vazifasini yaratamiz:
class Task implements Runnable {
private final int taskNumber;
public Task(int taskNumber) {
this.taskNumber = taskNumber;
}
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException ignored) {
}
System.out.printf("So'rov #%d id=%d oqimda qayta ishlangan\n", taskNumber, Thread.currentThread().getId());
}
}
Bu klass kelgan so'rovning qayta ishlanishini va uning raqamini chiqaradi.
Keyin main metodida biz bitta oqimlik ExecutorService yaratamiz va kelgan so'rovlarni ketma-ket qayta ishlaymiz. 30 soniya davomida qayta ishlash ko'rsatilgani uchun, 30 soniya tugagach, biz ExecutorService ni majburiy to'xtatamiz.
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 1_000; i++) {
executorService.execute(new Task(i));
}
executorService.awaitTermination(30, TimeUnit.SECONDS);
executorService.shutdownNow();
}
Ishga tushirganda biz konsolda quyidagi xabarlarni ko'ramiz:
So'rov #1 id=16 oqimda qayta ishlangan
So'rov #2 id=16 oqimda qayta ishlangan
….
So'rov #29 id=16 oqimda qayta ishlangan
30 soniya davomida so'rovlar qayta ishlangandan so'ng executorService da shutdownNow() metodi chaqiriladi, bu joriy vazifani to'xtatadi va bajarishni kutayotgan barcha vazifalarni bekor qiladi. Shundan keyin dastur muvaffaqiyatli tugashini ko'ramiz.
Agar biron vazifa noto'g'ri bajarilib, hatto bizning yagona puldagi oqimimizni ham tugatsagina, bu har doim ham mukammal bo'lmaydi. Biz bunday vaziyatni simulyatsiya qilamiz, bu bizning yagona oqim bilan ExecutorService qanday ishlashini tushunishga yordam beradi.
Buning uchun vazifalardan biri bajarilayotganda eskirgan va xavfli Thread.currentThread().stop() metodi yordamida oqimimizni tugatamiz. Biz buni aynan oqimning bir vazifasi ustida tugashini simulyatsiya qilish uchun qilamiz.
Task klassidagi run metodini o'zgartiramiz:
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException ignored) {
}
if (taskNumber == 5) {
Thread.currentThread().stop();
}
System.out.printf("So'rov #%d id=%d oqimda qayta ishlangan\n", taskNumber, Thread.currentThread().getId());
}
Biz 5-raqamli vazifada to'xtatamiz.
Oqimning 5-raqamli vazifa tugashida to'xtatilganidan keyingi chiqishni ko'ramiz:
So'rov #1 id=16 oqimda qayta ishlangan
So'rov #2 id=16 oqimda qayta ishlangan
So'rov #3 id=16 oqimda qayta ishlangan
So'rov #4 id=16 oqimda qayta ishlangan
So'rov #6 id=17 oqimda qayta ishlangan
So'rov #7 id=17 oqimda qayta ishlangan
…
So'rov #29 id=17 oqimda qayta ishlangan
Ko'ramizki, 5-vazifa tugashi bilan oqim id=16 dan id=17 ga o'tdi. Bu - executorService to'xtatilgan oqimni yangisiga almashtirib, vazifalar davom etmoqda.
newSingleThreadExecutor dan foydalanish ketma-ket vazifalarni bajarish uchun zarur va bu faqat bitta vazifa bir vaqtning o'zida bajarilgan vaziyatda talab qilinadi, lekin navbatdagi vazifalarni bajarishda davom etma majburiyatini qoldiradi, hatto vazifa qanday tugashidan qat'i nazar (bir vazifada oqim o'lib qolishi mumkin) bo'lsa ham.
ThreadFactory
Oqimlarni yaratish va qayta yaratish haqida gapirganda, biz ThreadFactory haqida ham ayta olmaymiz.
ThreadFactory — bu talab bo'yicha yangi oqimlar yaratadigan ob'ekt.
Biz o'z oqimlarimiz fabrikasini yaratib, uni Executors.newSingleThreadExecutor(ThreadFactory threadFactory) metodiga uzatishimiz mumkin.
|
Yangi oqim yaratish metodini konstruktorida nom berib qayta yozdik. |
|
Yaratilayotgan oqim uchun nom va prioritetni o'zgartirdik. |
Shunday qilib, Executors.newSingleThreadExecutor ning ikki xil bo'lgan metodlari mavjudligini aniqladik. Biri - parametrsiz, ikkinchisi - ThreadFactory tipidagi parametr bilan.
ThreadFactory yordamida yaratilayotgan oqimlarni turli sozlamalar bilan ta'minlash mumkin, masalan, - prioritetlarni o'rnatish, oqimlar osti klasslarini ishlatish, UncaughtExceptionHandler oqimi qo'shish va hokazo.
GO TO FULL VERSION