Eng oddiy dasturga nazar tashlaymiz:
public static void main(String[] args) throws Exception {
// 3 ga teng bo'lgan fixer thread pool bilan ExecutorService yaratamiz
ExecutorService service = Executors.newFixedThreadPool(3);
// ExecutorService ga oddiy Runnable vazifasini uzatamiz
service.submit(() -> System.out.println("bajarildi"));
}
Dastur ishga tushganda, konsolda kutilgan natija olinadi:
Lekin keyin IntellijIDEA uchun odatiy chiqishni ko'rmaymiz:
Buni odatda dastur yakunida ko'rish mumkin.
Nima uchun shunday bo'lmoqda?
Metod newFixedThreadPool() tavsifidan, bu ExecutorService orqali yaratilgan iplar ochiq to'xtatilmaguncha mavjud bo'lishda davom etishini bilib olamiz. Demak, biz bir vazifani ExecutorService ga topshirganimizda, bu vazifani bajarish uchun ip yaratilgan va vazifa bajarilgandan keyin ham mavjud bo'lgan.
ExecutorService To'xtatish
Xo'sh, ExecutorService ortidan “yopish” (to'xtatish) zarur. Buni ikki usulda amalga oshirish mumkin:
void shutdown() — bu metod chaqirilgandan so'ng ExecutorService yangi vazifalarni qabul qilmaydi. Oldinroq ExecutorService ga berilgan barcha vazifalar bajarilishini davom ettiradi.
public static void main(String[] args) throws Exception { ExecutorService service = Executors.newFixedThreadPool(3); service.submit(() -> System.out.println("vazifa 1")); service.submit(() -> System.out.println("vazifa 2")); service.shutdown(); // bu erda RejectedExecutionException sodir bo'ladi service.submit(() -> System.out.println("vazifa 3")); }List<Runnable> shutdownNow() — metod mavjud faol vazifalarni to'xtatishga harakat qiladi. Qator kutib turgan vazifalar tashlanadi va Runnable ro'yxati shaklida qaytariladi.
public static void main(String[] args) throws Exception { ExecutorService service = Executors.newFixedThreadPool(5); List.of(1, 2, 3, 4, 5, 6, 7, 8).forEach(i -> service.submit(() -> System.out.println(i))); List<Runnable> runnables = service.shutdownNow(); runnables.forEach(System.out::println); }
Dastur chiqishi:
2
4
3
java.util.concurrent.FutureTask@1e80bfe8[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@4edde6e5[Wrapped task = Test$$Lambda$16/0x0000000800b95040@70177ecd]]
java.util.concurrent.FutureTask@cc34f4d[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@66a29884[Wrapped task = Test$$Lambda$16/0x0000000800b95040@4769b07b]]
java.util.concurrent.FutureTask@6f539caf[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@17a7cec2[Wrapped task = Test$$Lambda$16/0x0000000800b95040@65b3120a]]
5
Jarayon yakunlandi, chiqish kodi 0
Chiqish ishga tushirishdan ishga tushirishga farq qiladi. Chiqishda 2 xil satrlar mavjud:
raqam — bu vazifa ExecutorService tomonidan amalga oshirilgan va vazifalar ro'yxatidan raqam chiqarildi.
FutureTask turidagi ob'ekt, uning toString() metodi chaqirilgandan keyin. Bu ExecutorService ga topshirilgan vazifalar, lekin bajarilmagan.
Bu chiqishda yana bir qiziqarli narsa bor. Agar biz ideal dunyoda yashayotgan bo'lsak, barcha raqamlar birinchi chiqarilgan bo'lar edi va keyin FutureTask turidagi ob'ektlar. Ammo sinxronizatsiya muammolari tufayli chiqishdagi satrlar aralashgan.
Boshqa metodlar
Bundan tashqari, ExecutorService ni to'xtatish bilan bog'liq yana bir nechta metodlar mavjud:
boolean awaitTermination(long timeout, TimeUnit unit) — metod uni chaqirgan ipni bloklaydi. Blokirovka quyidagi uchta voqeadan biri sodir bo'lganda bekor qilinadi:
- shutdown() metodi chaqirilgandan so'ng, barcha faol vazifalar va navbatdagi barcha vazifalar bajarildi;
- metod parametrlari orqali belgilangan vaqtdan o'tdi;
- awaitTermination() metodini chaqirgan ip uzildi.
Metod true qaytaradi, agar ExecutorService timeout tugashidan oldin to'xtatilgan bo'lsa, va false, agar timeout oldinroq tugagan bo'lsa.
public static void main(String[] args) throws Exception { ExecutorService service = Executors.newFixedThreadPool(2); service.submit(() -> System.out.println("vazifa 1")); service.submit(() -> System.out.println("vazifa 2")); service.submit(() -> System.out.println("vazifa 3")); service.shutdown(); System.out.println(service.awaitTermination(1, TimeUnit.MICROSECONDS)); }boolean isShutdown() — true qaytaradi, agar ExecutorService ga shutdown() yoki shutdownNow() metodi chaqirilgan bo'lsa.
public static void main(String[] args) throws Exception { ExecutorService service = Executors.newFixedThreadPool(2); service.submit(() -> System.out.println("vazifa 1")); service.submit(() -> System.out.println("vazifa 2")); service.submit(() -> System.out.println("vazifa 3")); System.out.println(service.isShutdown()); service.shutdown(); System.out.println(service.isShutdown()); }boolean isTerminated() — true qaytaradi, agar ExecutorService ga shutdown() yoki shutdownNow() chaqirilib, barcha vazifalar bajarilgan bo'lsa.
public static void main(String[] args) throws Exception { ExecutorService service = Executors.newFixedThreadPool(5); List.of(1, 2, 3, 4, 5, 6, 7, 8).forEach(i -> service.submit(() -> System.out.println(i))); service.shutdownNow(); System.out.println(service.isTerminated()); }
Ko'rib chiqilgan metodlardan foydalanilgan kod namunasi:
public static void main(String[] args) throws Exception {
ExecutorService service = Executors.newFixedThreadPool(16);
Callable<String> task = () -> {
Thread.sleep(1);
return "Tugadi";
};
// 10 mingta vazifani bajarishga qo'shamiz
List<Future<String>> futures = IntStream.range(0, 10_000)
.mapToObj(i -> service.submit(task))
.collect(Collectors.toList());
System.out.printf("Bajarishga yuborilgan %d vazifalar.%n", futures.size());
// yopishga harakat qilamiz
service.shutdown();
// 100 millisekund davomida ishning tugashini kutamiz
if (service.awaitTermination(100, TimeUnit.MILLISECONDS)) {
System.out.println("Barcha vazifalar bajarildi!");
} else {
// majburan to'xtatamiz
List<Runnable> notExecuted = service.shutdownNow();
System.out.printf("Ishga tushmagan %d vazifalar.%n", notExecuted.size());
}
System.out.printf("Jami bajarilgan %d vazifalar.%n", futures.stream().filter(Future::isDone).count());
}
Dastur chiqishi (ishga tushirishdan ishga tushirishga farq qiladi):
Ishga tushmagan 9170 vazifalar.
Jami bajarilgan 830 vazifalar.
Jarayon yakunlandi, chiqish kodi 0
GO TO FULL VERSION