
103. چه قوانینی برای بررسی استثنایی در حین وراثت اعمال می شود؟
اگر من سوال را درست متوجه شده باشم، آنها در مورد قوانینی برای کار با استثنا در هنگام ارث می پرسند. قوانین مربوطه به شرح زیر است:- یک متد لغو یا پیادهسازی شده در یک نسل/پیادهسازی نمیتواند استثناهای بررسی شده را که در سلسله مراتب بالاتر از استثناهای یک متد سوپرکلاس/اینترفیس هستند، ایجاد کند.
public interface Animal {
void speak() throws IOException;
}
هنگام پیادهسازی این رابط، نمیتوانیم یک استثنای پرتابپذیر عمومیتر (مثلاً Exception ، Throwable ) را در معرض نمایش بگذاریم، اما میتوانیم استثنای موجود را با زیر کلاس جایگزین کنیم، مانند FileNotFoundException :
public class Cat implements Animal {
@Override
public void speak() throws FileNotFoundException {
// Some implementation
}
}
- عبارت throws سازنده کلاس فرعی باید شامل تمام کلاس های استثنا باشد که توسط سازنده سوپرکلاس فراخوانده شده برای ایجاد شیء پرتاب شده است.
public class Animal {
public Animal() throws ArithmeticException, NullPointerException, IOException {
}
سپس یک سازنده زیر کلاس نیز باید آنها را پرتاب کند:
public class Cat extends Animal {
public Cat() throws ArithmeticException, NullPointerException, IOException {
super();
}
یا، مانند روشها، میتوانید استثناهای متفاوت و کلیتری را مشخص کنید. در مورد ما، میتوانیم Exception را نشان دهیم ، زیرا کلیتر است و جد مشترک هر سه استثنا است که در superclass نشان داده شدهاند:
public class Cat extends Animal {
public Cat() throws Exception {
super();
}
104. آیا می توانید کدی بنویسید که بلوک نهایی اجرا نشود؟
اول، بیایید به یاد بیاوریم که در نهایت چیست. قبلاً، مکانیسم ثبت استثنا را بررسی کردیم: یک بلوک try مشخص میکند که در آن استثناها گرفته میشوند، و بلوکهای catch کدی هستند که وقتی یک استثنای مربوطه گرفته میشود، فراخوانی میشوند. سومین بلوک کد که با کلمه کلیدی نهایی مشخص شده است ، می تواند جایگزین یا بعد از بلوک های catch شود. ایده پشت این بلوک این است که کد آن همیشه بدون توجه به آنچه در یک بلوک try یا catch اتفاق می افتد (صرف نظر از اینکه استثنا وجود دارد یا خیر) اجرا می شود. مواردی که این بلوک اجرا نمی شود نادر هستند و غیرعادی هستند. ساده ترین مثال زمانی است که System.exit(0) قبل از بلوک نهایی فراخوانی می شود و در نتیجه برنامه خاتمه می یابد:try {
throw new IOException();
} catch (IOException e) {
System.exit(0);
} finally {
System.out.println("This message will not be printed on the console");
}
همچنین شرایط دیگری وجود دارد که بلوک نهایی اجرا نمی شود:
-
به عنوان مثال، یک خاتمه غیرعادی برنامه ناشی از خطاهای مهم سیستم، یا برخی از خطاهایی که باعث از کار افتادن برنامه می شود (به عنوان مثال، StackOverflowError ، که زمانی رخ می دهد که پشته برنامه سرریز می شود).
-
وضعیت دیگر زمانی است که یک نخ شبح وارد یک بلوک try- end می شود، اما سپس رشته اصلی برنامه خاتمه می یابد. به هر حال، موضوعات شبح برای کارهای پسزمینهای هستند که اولویت بالایی یا اجباری ندارند، بنابراین برنامه منتظر نمیماند تا آنها تمام شود.
-
بیاهمیتترین مثال، یک حلقه بیپایان در داخل یک بلوک try یا catch است - زمانی که داخل آن قرار گیرد، یک نخ برای همیشه در آنجا گیر میکند:
try { while (true) { } } finally { System.out.println("This message will not be printed on the console"); }

105. مثالی بنویسید که در آن چندین استثنا را در یک بلوک catch مدیریت کنید.
1) مطمئن نیستم که این سوال درست پرسیده شده باشد. تا جایی که من متوجه شدم، این سوال به چندین بلوک گرفتن و یک امتحان اشاره دارد :try {
throw new FileNotFoundException();
} catch (FileNotFoundException e) {
System.out.print("Oops! There was an exception: " + e);
} catch (IOException e) {
System.out.print("Oops! There was an exception: " + e);
} catch (Exception e) {
System.out.print("Oops! There was an exception: " + e);
}
اگر یک استثنا در یک بلوک try انداخته شود ، بلوکهای catch مرتبط سعی میکنند آن را بهطور متوالی از بالا به پایین بگیرند. وقتی استثنا با یکی از بلوکهای catch مطابقت داشت ، بلوکهای باقیمانده دیگر نمیتوانند آن را بگیرند و مدیریت کنند. همه اینها به این معنی است که استثناهای باریک بالاتر از موارد کلی تر در مجموعه بلوک های catch مرتب شده اند . برای مثال، اگر اولین بلوک catch ما کلاس Exception را بگیرد ، بلوکهای بعدی استثناهای بررسی شده را نمیگیرند (یعنی بلاکهای باقیمانده با زیر کلاسهای Exception کاملاً بیفایده خواهند بود). 2) یا شاید سوال به درستی پرسیده شده است. در آن صورت، میتوانیم استثنائات را به صورت زیر مدیریت کنیم:
try {
throw new NullPointerException();
} catch (Exception e) {
if (e instanceof FileNotFoundException) {
// Some handling that involves a narrowing type conversion: (FileNotFoundException)e
} else if (e instanceof ArithmeticException) {
// Some handling that involves a narrowing type conversion: (ArithmeticException)e
} else if(e instanceof NullPointerException) {
// Some handling that involves a narrowing type conversion: (NullPointerException)e
}
پس از استفاده از catch برای گرفتن یک استثنا، سپس سعی می کنیم نوع خاص آن را با استفاده از عملگر instanceof کشف کنیم ، که بررسی می کند آیا یک شی به یک نوع خاص تعلق دارد یا خیر. این به ما امکان می دهد تا بدون ترس از عواقب منفی، تبدیل نوع باریک را با اطمینان انجام دهیم. ما میتوانیم هر یک از این رویکردها را در شرایط مشابه اعمال کنیم. من در مورد سوال فقط به این دلیل ابراز تردید کردم که گزینه دوم را رویکرد خوبی نمی نامم. در تجربهام، هرگز با آن برخورد نکردهام، و اولین رویکردی که شامل چندین بلوک گیر است، گسترده است.
106. کدام عملگر به شما اجازه می دهد تا یک استثنا را مجبور کنید که پرتاب شود؟ یک مثال بنویسید
من قبلاً چندین بار در مثال های بالا از آن استفاده کرده ام، اما یک بار دیگر آن را تکرار می کنم: کلمه کلیدی throw . مثالی از پرتاب دستی یک استثنا:throw new NullPointerException();
107. آیا روش اصلی می تواند استثناء ایجاد کند؟ اگر چنین است، پس کجا می رود؟
اول از همه، می خواهم توجه داشته باشم که روش اصلی چیزی بیش از یک روش معمولی نیست. بله، برای شروع اجرای یک برنامه توسط ماشین مجازی فراخوانی می شود، اما فراتر از آن، می توان آن را از هر کد دیگری فراخوانی کرد. این بدان معناست که آن را نیز تابع قوانین معمول در مورد نشان دادن استثناهای علامتدار بعد از کلمه کلیدی throws است :public static void main(String[] args) throws IOException {
بر این اساس، می تواند استثناهایی را ایجاد کند. وقتی main به عنوان نقطه شروع برنامه نامیده می شود (به جای روش دیگری)، هر استثنایی که ایجاد می کند توسط UncaughtExceptionHandler
مدیریت می شود . هر نخ دارای یک چنین کنترل کننده است (یعنی در هر رشته یک چنین کنترل کننده وجود دارد). در صورت لزوم، میتوانید کنترلکننده خود را ایجاد کرده و با فراخوانی عمومی static void main(String[] args) throws IOException {setDefaultUncaughtExceptionHandler متد در یک public static void main(String[] args) IOException {Thread object.
چند رشته ای

108. چه مکانیسم هایی برای کار در محیط چند رشته ای می شناسید؟
مکانیسم های اصلی برای چند رشته ای در جاوا عبارتند از:-
کلمه کلیدی همگام سازی شده ، که راهی برای یک رشته برای قفل کردن یک روش/بلاک در هنگام ورود است و از ورود رشته های دیگر جلوگیری می کند.
-
کلمه کلیدی فرار ، دسترسی ثابت به متغیری را که رشته های مختلف به آن دسترسی دارند، تضمین می کند. یعنی وقتی این اصلاح کننده روی یک متغیر اعمال می شود، تمام عملیات اختصاص دادن و خواندن آن متغیر اتمی می شود. به عبارت دیگر، رشته ها متغیر را در حافظه محلی خود کپی نمی کنند و آن را تغییر نمی دهند. ارزش اصلی آن را تغییر خواهند داد.
-
Runnable - ما می توانیم این رابط (که از یک متد run() منفرد تشکیل شده است ) در برخی کلاس ها پیاده سازی کنیم:
public class CustomRunnable implements Runnable { @Override public void run() { // Some logic } }
و هنگامی که یک شی از آن کلاس ایجاد می کنیم، می توانیم یک رشته جدید را با ارسال شیء خود به سازنده Thread و سپس فراخوانی متد start() شروع کنیم :
Runnable runnable = new CustomRunnable(); new Thread(runnable).start();
متد start ، متد run() پیاده سازی شده را روی یک رشته مجزا اجرا می کند .
-
Thread - ما می توانیم این کلاس را به ارث ببریم و روش اجرای آن را لغو کنیم :
public class CustomThread extends Thread { @Override public void run() { // Some logic } }
ما می توانیم با ایجاد یک شی از این کلاس و سپس فراخوانی متد start() یک رشته جدید راه اندازی کنیم :
new CustomThread().start();
- Concurrency - این مجموعه ای از ابزارها برای کار در یک محیط چند رشته ای است.
متشکل از:
-
مجموعههای همزمان - مجموعهای از مجموعههایی است که به صراحت برای کار در یک محیط چند رشتهای ایجاد شدهاند.
-
صف - صف های تخصصی برای یک محیط چند رشته ای (مسدود و غیر مسدود).
-
همگامسازها - اینها ابزارهای تخصصی برای کار در یک محیط چند رشتهای هستند.
-
مجریان - مکانیسم هایی برای ایجاد استخرهای نخ.
-
قفل ها - مکانیسم های همگام سازی نخ ها که نسبت به موارد استاندارد انعطاف پذیرتر هستند (همگام، منتظر، اطلاع رسانی، اطلاع رسانی به همه).
- Atomics - کلاس های بهینه شده برای چند رشته ای. هر یک از عملیات آنها اتمی است.
-
109. در مورد همگام سازی بین رشته ها به ما بگویید. متدهای wait()، notify()، notifyAll() و join() برای چیست؟
همگام سازی بین رشته ها مربوط به کلمه کلیدی همگام شده است . این اصلاح کننده را می توان مستقیماً روی بلوک قرار داد:synchronized (Main.class) {
// Some logic
}
یا مستقیماً در امضای متد:
public synchronized void move() {
// Some logic }
همانطور که قبلاً گفتم، synchronized مکانیزمی برای قفل کردن یک بلوک/روش به رشته های دیگر پس از ورود یک رشته است. بیایید یک بلوک/روش کد را به عنوان یک اتاق در نظر بگیریم. مقداری نخ به اتاق نزدیک می شود، وارد اتاق می شود و در را با کلیدش قفل می کند. وقتی نخ های دیگر به اتاق نزدیک می شوند، می بینند که در قفل است و در همان نزدیکی منتظر می مانند تا اتاق در دسترس قرار گیرد. هنگامی که اولین نخ با کار خود در اتاق تمام شد، در را باز می کند، اتاق را ترک می کند و کلید را رها می کند. من چند بار به یک دلیل به یک کلید اشاره کردم - زیرا چیزی مشابه واقعا وجود دارد. این یک شی خاص است که حالت اشغال/آزاد دارد. هر شی در جاوا چنین شی ای دارد، بنابراین وقتی از بلوک همگام سازی شده استفاده می کنیم ، باید از پرانتز برای نشان دادن شی ای که mutex آن قفل می شود استفاده کنیم:
Cat cat = new Cat();
synchronized (cat) {
// Some logic
}
ما همچنین میتوانیم از mutex مرتبط با یک کلاس استفاده کنیم، همانطور که در مثال اول انجام دادم ( Main.class ). به هر حال، وقتی از synchronized روی یک متد استفاده می کنیم، شی مورد نظر را که می خواهیم قفل کنیم را مشخص نمی کنیم، درست است؟ در این حالت، برای متدهای غیراستاتیک، mutex قفل شده، شی this است ، یعنی شی فعلی کلاس. برای روشهای استاتیک، mutex مرتبط با کلاس فعلی ( this.getClass(); ) قفل میشود. Wait() متدی است که mutex را آزاد می کند و thread فعلی را در حالت انتظار قرار می دهد، گویی به مانیتور فعلی متصل می شود (چیزی شبیه یک لنگر). به همین دلیل، این روش را فقط می توان از یک بلوک یا متد هماهنگ فراخوانی کرد. در غیر این صورت، منتظر چه چیزی بود و چه چیزی منتشر می شد؟). همچنین توجه داشته باشید که این متد از کلاس Object است . خوب، نه یک، بلکه سه:
-
Wait() رشته فعلی را در حالت انتظار قرار می دهد تا زمانی که رشته دیگری متد notify() یا notifyAll() را روی این شیء فراخوانی کند (در ادامه در مورد این متدها صحبت خواهیم کرد).
-
Wait(long timeout) رشته فعلی را در حالت انتظار قرار می دهد تا زمانی که رشته دیگری متد notify() یا notifyAll() را روی این شیء فراخوانی کند یا بازه زمانی مشخص شده توسط timeout منقضی شود.
-
انتظار (تایم اوت طولانی، نانوهای داخلی) مانند روش قبلی است، اما در اینجا نانو به شما امکان میدهد نانوثانیهها را مشخص کنید (تایم اوت دقیقتر).
-
notify() به شما امکان می دهد تا یک رشته تصادفی را که در بلوک همگام سازی فعلی منتظر است، بیدار کنید. باز هم، این روش را فقط می توان در یک بلوک یا روش همگام فراخوانی کرد (به هر حال، در جاهای دیگر کسی برای بیدار شدن وجود نخواهد داشت).
-
notifyAll() تمام رشته های منتظر در مانیتور فعلی را بیدار می کند (همچنین فقط در یک بلوک یا روش همگام استفاده می شود ).
110. چگونه یک نخ را متوقف کنیم؟
اولین چیزی که در اینجا باید بگوییم این است که وقتی run() تا پایان کامل می شود، رشته به طور خودکار خاتمه می یابد. اما گاهی اوقات می خواهیم قبل از انجام روش، یک نخ را زودتر از موعد مقرر بکشیم. پس چه کار کنیم؟ شاید بتوانیم از متد stop() روی شی Thread استفاده کنیم ؟ جواب منفی! این روش منسوخ شده است و ممکن است باعث خرابی سیستم شود.
public class CustomThread extends Thread {
private boolean isActive;
public CustomThread() {
this.isActive = true;
}
@Override
public void run() {
{
while (isActive) {
System.out.println("The thread is executing some logic...");
}
System.out.println("The thread stopped!");
}
}
public void stopRunningThread() {
isActive = false;
}
}
فراخوانی متد stopRunningThread() پرچم داخلی را روی false قرار می دهد و باعث خاتمه متد run() می شود. بیایید آن را به صورت اصلی بنامیم :
System.out.println("Program starting...");
CustomThread thread = new CustomThread();
thread.start();
Thread.sleep(3);
// As long as our main thread is asleep, our CustomThread runs and prints its message on the console
thread.stopRunningThread();
System.out.println("Program stopping...");
در نتیجه، چیزی شبیه به این را در کنسول خواهیم دید:
public class CustomThread extends Thread {
@Override
public void run() {
{
while (!Thread.interrupted()) {
System.out.println("The thread is executing some logic...");
}
System.out.println("The thread stopped!");
}
}
}
در حال اجرا به صورت اصلی :
System.out.println("Program starting...");
Thread thread = new CustomThread();
thread.start();
Thread.sleep(3);
thread.interrupt();
System.out.println("Program stopping...");
نتیجه اجرای این همان حالت اول است، اما من این روش را بیشتر دوست دارم: کد کمتری نوشتیم و از عملکردهای آماده و استاندارد بیشتری استفاده کردیم. خوب، برای امروز همین است!
GO TO FULL VERSION