دستگرمی ششم

دستگرمی این هفته:
برنامه زیر را ببینید:
public class JT { static final Help help = new Help(); public static void main(String[] args) { Arrays.asList(new Operation(1), new Operation(2), new Operation(3)) .forEach(Operation::start); } } class Operation extends Thread { private int count; public Operation(int count) { this.count = count; } @Override public void run() { try { System.out.println(count); JT.help.bl(); System.out.println("end"); } catch (InterruptedException e) { System.out.print("catch"); } } } class Help { private final Integer PIVOT = 3; private int counter = 0; public void bl() throws InterruptedException { synchronized (PIVOT) { if (++counter == PIVOT) { PIVOT.notifyAll(); return; } } synchronized (PIVOT) { PIVOT.wait(); } } }
در رابطه با خروجی کد فوق، کدام گزینه صحیح است؟
- خروجی برنامه ترکیبی از اعداد و عبارتهای end میباشد که ترتیب مشخصی ندارند. (50%, 1 رای)
- برنامه بدون خطا اجرا شده و تضمین میشود تمامی اعداد قبل از چاپ شدن سه عبارت end چاپ شوند. (50%, 1 رای)
- برای یکی از نخها عبارت catch چاپ میشود. (0%, 0 رای)
- پس از چاپ اولین عدد، برنامه در متد bl دچار DeadLock شده و متوقف میشود. (0%, 0 رای)
مجموع رای ها: 2

پاسخ
پاسخ صحیح: برنامه بدون خطا اجرا شده و تضمین میشود تمامی اعداد قبل از چاپ شدن سه عبارت end چاپ شوند.
برای هر شی از کلاس Help ، ابتدا مقدار متغیر counter برابر صفر قرار داده میشود سپس در هر فراخوانی متد bl توسط یک نخ خاص، وارد بلوک synchronized با قفل شی PIVOT میشویم. بنابراین حداکثر یک نخ در هر لحظه میتواند این بلوک را اجرا کند و باقی نخهایی که قفل شی PIVOT را میخواهند منتظر پایان کار نخی که ناحیهی بحرانی را اجرا میکند میماند. نخی که داخل بلوک synchronized را اجرا میکند قبل از ارزیابی شرط if مقدار متغیر counter را یکی افزایش میدهد. تا زمانی که مقدار counter برای شی Help به 3 یا همان PIVOT نرسیده باشد، بلوک if اجرا نشده و پس از خروج از بلوک synchronized اول وارد بلوک بعد میشویم. این بلوک نیز قفل شی PIVOT را میگیرد اما تفاوت آن فراخوانی متد wait روی PIVOT است. با رسیدن به فراخوانی این متد، قفل PIVOT آزاد میشود. بنابراین نخهایی که بلوک if را اجرا نمیکنند در متد wait منتظر notify شدن میمانند و در عین حال قفل شی PIVOT را نیز آزاد میکنند تا باقی نخها بتوانند وارد بلوک synchronized اول متد شوند و برنامه دچار DeadLock نشود. اما نخی که مقدار counter در شرط if برای آن 3 خواهد شد، تمامی waitها روی شی PIVOT، nofityAll میشوند و خود نخ نیز از متد خارج میشود. وجود دستور return در بلوک if مهم است، بدون این دستور نخ آخر وارد قسمت wait شده و بدون nofity شدن منتظر میماند.
در مجموع میتوان عملکرد کلاس Help را مانند یک شی CyclicBarrier با وضعیت 3 دانست. یعنی تا زمانی که نخ سوم متد bl را اجرا نکند، نخهای قبلی در آن متد منتظر خواهند ماند.
در متد main برنامه لیستی از سه شی کلاس Operation ساخته شده و هرکدام براساس method reference ایجاد شده در متد forEach، با متد start کار خود را در یک نخ جدا شروع میکنند. در متد run هریک از نخها ابتدا مقدار count چاپ و سپس اچرای متد bl روی شی help از کلاس JT آغاز میشود. اکنون میدانیم که تا زمانی که شی سوم Operation متد bl را اجرا نکند، باقی نخها در آن متد خواهند ماند. اما پس از آن که هر سه نخ به این متد برسند، اجرای آنها با هم ادامه مییابد و هرکدام عبارت end را چاپ خواهد کرد.
در اجرای این برنامه خطایی رخ نمیدهد پس درخروجی استاندارد عبارت catch چاپ نمیشود. همچنین با توجه به عملکرد متد bl میتوان دریافت که خروجی برنامه شامل اعداد 1، 2 و 3 میباشد که ترتیب خاصی ندارند و پس از چاپ اعداد عبارت end برای هر سه نخ چاپ میشود.
.
.
.
آدرس کانال تلگرام: JavaCupIR@
آدرس اکانت توییتر: JavaCupIR@
آدرس صفحه اینستاگرام: javacup.ir
آدرس گروه لینکدین: Iranian Java Developers