CodeGym /وبلاگ جاوا /Random-FA /50 پرسش و پاسخ برتر مصاحبه شغلی برای Java Core. قسمت 2
John Squirrels
مرحله
San Francisco

50 پرسش و پاسخ برتر مصاحبه شغلی برای Java Core. قسمت 2

در گروه منتشر شد
50 پرسش و پاسخ برتر مصاحبه شغلی برای Java Core. قسمت 1 50 پرسش و پاسخ برتر مصاحبه شغلی برای Java Core.  قسمت 2 - 1

چند رشته ای

24. چگونه می توانم یک موضوع جدید در جاوا ایجاد کنم؟

به هر شکلی، یک رشته با استفاده از کلاس Thread ایجاد می شود. اما راه های مختلفی برای این کار وجود دارد…
  1. java.lang.thread را به ارث ببرید .
  2. رابط java.lang.Runnable را پیاده سازی کنید - سازنده کلاس Thread یک شی Runnable می گیرد.
بیایید در مورد هر یک از آنها صحبت کنیم.

کلاس Thread را به ارث ببرید

در این حالت، کلاس ما را به ارث می برد java.lang.Thread . این یک متد run() دارد و این همان چیزی است که ما نیاز داریم. تمام عمر و منطق تاپیک جدید در این روش خواهد بود. این به نوعی مانند یک روش اصلی برای موضوع جدید است. پس از آن، تنها چیزی که باقی می ماند این است که یک شی از کلاس خود ایجاد کنیم و متد start() را فراخوانی کنیم . این یک موضوع جدید ایجاد می کند و شروع به اجرای منطق آن می کند. بیا یک نگاهی بیندازیم:
/**
* An example of how to create threads by inheriting the {@link Thread} class.
*/
class ThreadInheritance extends Thread {

   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName());
   }

   public static void main(String[] args) {
       ThreadInheritance threadInheritance1 = new ThreadInheritance();
       ThreadInheritance threadInheritance2 = new ThreadInheritance();
       ThreadInheritance threadInheritance3 = new ThreadInheritance();
       threadInheritance1.start();
       threadInheritance2.start();
       threadInheritance3.start();
   }
}
خروجی کنسول چیزی شبیه به این خواهد بود:
Thread-1 Thread-0 Thread-2
یعنی حتی در اینجا می بینیم که نخ ها به ترتیب اجرا نمی شوند، بلکه همانطور که JVM برای اجرای آنها مناسب می بیند :)

رابط Runnable را پیاده سازی کنید

اگر مخالف وراثت هستید و/یا قبلاً کلاس دیگری را به ارث برده اید، می توانید از رابط java.lang.Runnable استفاده کنید . در اینجا، کلاس خود را با پیاده سازی متد run() مانند مثال بالا، این رابط را پیاده سازی می کنیم . تنها چیزی که باقی می ماند ایجاد اشیاء Thread است. به نظر می رسد که خطوط بیشتر کد بدتر هستند. اما می دانیم که ارث چقدر زیانبار است و بهتر است به هر طریقی از آن اجتناب کنیم ;) نگاهی بیندازید:
/**
* An example of how to create threads from the {@link Runnable} interface.
* It's easier than easy — we implement this interface and then pass an instance of our object
* to the constructor.
*/
class ThreadInheritance implements Runnable {

   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName());
   }

   public static void main(String[] args) {
       ThreadInheritance runnable1 = new ThreadInheritance();
       ThreadInheritance runnable2 = new ThreadInheritance();
       ThreadInheritance runnable3 = new ThreadInheritance();

       Thread threadRunnable1 = new Thread(runnable1);
       Thread threadRunnable2 = new Thread(runnable2);
       Thread threadRunnable3 = new Thread(runnable3);

       threadRunnable1.start();
       threadRunnable2.start();
       threadRunnable3.start();
   }
}
و این هم نتیجه:
Thread-0 Thread-1 Thread-2

25. تفاوت بین یک فرآیند و یک نخ چیست؟

50 پرسش و پاسخ برتر مصاحبه شغلی برای Java Core.  قسمت 2 - 2یک فرآیند و یک نخ به روش های زیر متفاوت هستند:
  1. یک برنامه در حال اجرا یک فرآیند نامیده می شود، اما یک نخ یک قطعه از یک فرآیند است.
  2. فرآیندها مستقل هستند، اما نخ ها قطعاتی از یک فرآیند هستند.
  3. فرآیندها دارای فضاهای آدرس متفاوتی در حافظه هستند، اما رشته ها فضای آدرس مشترکی دارند.
  4. جابجایی متن بین رشته ها سریعتر از جابجایی بین فرآیندها است.
  5. ارتباط بین فرآیندی کندتر و گرانتر از ارتباطات بین رشته ای است.
  6. هر گونه تغییر در یک فرآیند والد بر فرآیند فرزند تأثیر نمی گذارد، اما تغییر در یک رشته والد می تواند بر روی رشته فرزند تأثیر بگذارد.

26. مزایای چند رشته ای چیست؟

  1. Multithreading به یک برنامه/برنامه اجازه می دهد که همیشه به ورودی پاسخگو باشد، حتی اگر قبلاً برخی از وظایف پس زمینه را اجرا می کند.
  2. Multithreading انجام کارها را سریعتر ممکن می کند، زیرا رشته ها به طور مستقل اجرا می شوند.
  3. Multithreading استفاده بهتری از حافظه کش فراهم می کند، زیرا رشته ها می توانند به منابع حافظه مشترک دسترسی داشته باشند.
  4. Multithreading تعداد سرورهای مورد نیاز را کاهش می دهد، زیرا یک سرور می تواند چندین رشته را به طور همزمان اجرا کند.

27. حالات در چرخه عمر نخ چیست؟

50 پرسش و پاسخ برتر مصاحبه شغلی برای Java Core.  قسمت 2 - 3
  1. New: در این حالت، شی Thread با استفاده از عملگر جدید ایجاد می شود، اما رشته جدیدی هنوز وجود ندارد. تا زمانی که متد start() را فراخوانی نکنیم نخ شروع نمی شود .
  2. Runnable: در این حالت، thread آماده اجرا پس از start() است. روش نامیده می شود. با این حال، هنوز توسط زمان‌بندی رشته انتخاب نشده است.
  3. در حال اجرا: در این حالت، زمان‌بندی رشته رشته‌ای را از حالت آماده انتخاب می‌کند و اجرا می‌شود.
  4. Waiting/Blocked: در این حالت، یک رشته در حال اجرا نیست، اما هنوز زنده است یا منتظر است تا رشته دیگری تکمیل شود.
  5. Dead/Terminated: زمانی که یک رشته از متد run() خارج می شود ، در حالت مرده یا پایان یافته است.

28. آیا می توان یک تاپیک را دو بار اجرا کرد؟

نه، ما نمی‌توانیم یک رشته را دوباره راه‌اندازی کنیم، زیرا پس از شروع و اجرا یک رشته، به حالت Dead می‌رود. اگر سعی کنیم یک رشته را دو بار شروع کنیم، یک java.lang.IllegalThreadStateException پرتاب می شود. بیا یک نگاهی بیندازیم:
class DoubleStartThreadExample extends Thread {

   /**
    * Simulate the work of a thread
    */
   public void run() {
	// Something happens. At this state, this is not essential.
   }

   /**
    * Start the thread twice
    */
   public static void main(String[] args) {
       DoubleStartThreadExample doubleStartThreadExample = new DoubleStartThreadExample();
       doubleStartThreadExample.start();
       doubleStartThreadExample.start();
   }
}
به محض اینکه اجرا به شروع دوم همان رشته می رسد، یک استثنا وجود خواهد داشت. خودتان امتحان کنید ;) بهتر است این را یک بار ببینید تا صد بار در مورد آن بشنوید.

29. اگر مستقیماً run() را بدون فراخوانی start() فراخوانی کنید چه؟

بله، مطمئناً می‌توانید متد ()run را فراخوانی کنید ، اما یک رشته جدید ایجاد نمی‌شود و متد روی یک رشته مجزا اجرا نمی‌شود. در این حالت، یک شی معمولی داریم که یک متد معمولی را فراخوانی می کند. اگر ما در مورد متد ()start صحبت می کنیم ، پس این موضوع دیگری است. هنگامی که این متد فراخوانی می شود، JVM یک رشته جدید راه اندازی می کند. این تاپیک به نوبه خود روش ما را صدا می کند ;) باور نمی کنید؟ در اینجا، آن را امتحان کنید:
class ThreadCallRunExample extends Thread {

   public void run() {
       for (int i = 0; i < 5; i++) {
           System.out.print(i);
       }
   }

   public static void main(String args[]) {
       ThreadCallRunExample runExample1 = new ThreadCallRunExample();
       ThreadCallRunExample runExample2 = new ThreadCallRunExample();

       // Two ordinary methods will be called in the main thread, one after the other.
       runExample1.run();
       runExample2.run();
   }
}
و خروجی کنسول به شکل زیر خواهد بود:
0123401234
همانطور که می بینید هیچ موضوعی ایجاد نشد. همه چیز درست مثل یک کلاس معمولی کار می کرد. ابتدا متد شی اول و سپس دومی اجرا شد.

30. نخ دیمون چیست؟

نخ دیمون رشته ای است که وظایف را با اولویت کمتری نسبت به رشته دیگر انجام می دهد. به عبارت دیگر، وظیفه آن انجام کارهای کمکی است که فقط باید در ارتباط با یک رشته (اصلی) دیگر انجام شوند. بسیاری از موضوعات شبح وجود دارند که به طور خودکار اجرا می شوند، مانند جمع آوری زباله، نهایی کننده و غیره.

چرا جاوا یک thread دیمون را خاتمه می دهد؟

تنها هدف دیمون thread ارائه پشتیبانی پس‌زمینه از رشته کاربر است. بر این اساس، اگر thread اصلی خاتمه یابد، JVM به طور خودکار تمام رشته های شبح خود را خاتمه می دهد.

روش های کلاس Thread

کلاس java.lang.Thread دو روش برای کار با نخ شبح ارائه می دهد:
  1. public void setDaemon (وضعیت بولی) - این روش نشان می دهد که آیا این یک رشته شبح خواهد بود یا خیر. حالت پیش فرض غلط است . این بدان معنی است که تا زمانی که شما به طور خاص این موضوع را نگویید، هیچ رشته شبحی ایجاد نخواهد شد.
  2. public boolean isDaemon() - این روش اساساً یک گیرنده برای متغیر daemon است که با استفاده از روش قبلی تنظیم کردیم.
مثال:
class DaemonThreadExample extends Thread {

   public void run() {
       // Checks whether this thread is a daemon
       if (Thread.currentThread().isDaemon()) {
           System.out.println("daemon thread");
       } else {
           System.out.println("user thread");
       }
   }

   public static void main(String[] args) {
       DaemonThreadExample thread1 = new DaemonThreadExample();
       DaemonThreadExample thread2 = new DaemonThreadExample();
       DaemonThreadExample thread3 = new DaemonThreadExample();

       // Make thread1 a daemon thread.
       thread1.setDaemon(true);

       System.out.println("daemon? " + thread1.isDaemon());
       System.out.println("daemon? " + thread2.isDaemon());
       System.out.println("daemon? " + thread3.isDaemon());

       thread1.start();
       thread2.start();
       thread3.start();
   }
}
خروجی کنسول:
اهریمن، دیو؟ دیو واقعی؟ دیمون دروغین؟ thread کاذب thread کاربر موضوع thread کاربر
از خروجی می بینیم که در داخل خود thread می توانیم از متد static currentThread() استفاده کنیم تا بفهمیم کدام رشته است. از طرف دیگر، اگر به شی thread اشاره ای داشته باشیم، می توانیم مستقیماً از آن نیز مطلع شویم. این سطح لازم از پیکربندی را فراهم می کند.

31. آیا می توان نخ را بعد از ایجاد شبح ساخت؟

خیر. اگر سعی کنید این کار را انجام دهید، یک IllegalThreadStateException دریافت خواهید کرد . این بدان معنی است که ما فقط می توانیم قبل از شروع یک نخ شبح ایجاد کنیم. مثال:
class SetDaemonAfterStartExample extends Thread {

   public void run() {
       System.out.println("Working...");
   }

   public static void main(String[] args) {
       SetDaemonAfterStartExample afterStartExample = new SetDaemonAfterStartExample();
       afterStartExample.start();

       // An exception will be thrown here
       afterStartExample.setDaemon(true);
   }
}
خروجی کنسول:
در حال کار... استثنا در رشته "main" java.lang.IllegalThreadStateException در java.lang.Thread.setDaemon(Thread.java:1359) در SetDaemonAfterStartExample.main(SetDaemonExampleS.jat.

32. قلاب خاموشی چیست؟

قلاب خاموش کردن رشته ای است که به طور ضمنی قبل از خاموش شدن ماشین مجازی جاوا (JVM) فراخوانی می شود. بنابراین، هنگامی که ماشین مجازی جاوا به طور عادی یا غیرعادی خاموش می شود، می توانیم از آن برای انتشار یک منبع یا ذخیره حالت استفاده کنیم. می توانیم با استفاده از روش زیر یک قلاب خاموش کردن اضافه کنیم:
Runtime.getRuntime().addShutdownHook(new ShutdownHookThreadExample());
همانطور که در مثال نشان داده شده است:
/**
* A program that shows how to start a shutdown hook thread,
* which will be executed right before the JVM shuts down
*/
class ShutdownHookThreadExample extends Thread {

   public void run() {
       System.out.println("shutdown hook executed");
   }

   public static void main(String[] args) {

       Runtime.getRuntime().addShutdownHook(new ShutdownHookThreadExample());

       System.out.println("Now the program is going to fall asleep. Press Ctrl+C to terminate it.");
       try {
           Thread.sleep(60000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
   }
}
خروجی کنسول:
حالا برنامه به خواب می رود. Ctrl+C را فشار دهید تا آن را خاتمه دهید. قلاب خاموش شدن اجرا شد

33. همگام سازی چیست؟

در جاوا، همگام سازی توانایی کنترل دسترسی چندین رشته به هر منبع مشترک است. وقتی چندین رشته سعی می کنند یک کار را به طور همزمان انجام دهند، ممکن است نتیجه نادرستی دریافت کنید. برای رفع این مشکل، جاوا از همگام سازی استفاده می کند، که اجازه می دهد تنها یک رشته در یک زمان اجرا شود. همگام سازی را می توان به سه طریق به دست آورد:
  • همگام سازی یک روش
  • همگام سازی یک بلوک خاص
  • همگام سازی استاتیک

همگام سازی یک روش

یک روش همگام برای قفل کردن یک شی برای هر منبع مشترک استفاده می شود. هنگامی که یک رشته یک متد هماهنگ شده را فراخوانی می‌کند، به طور خودکار قفل شی را می‌گیرد و زمانی که رشته کار خود را کامل کرد، آن را آزاد می‌کند. برای انجام این کار، باید کلمه کلیدی همگام شده را اضافه کنید . با نگاه کردن به یک مثال می‌توانیم ببینیم که چگونه این کار می‌کند:
/**
* An example where we synchronize a method. That is, we add the synchronized keyword to it.
* There are two authors who want to use one printer. Each of them has composed their own poems
* And of course they don’t want their poems mixed up. Instead, they want work to be performed in * * * order for each of them
*/
class Printer {

   synchronized void print(List<String> wordsToPrint) {
       wordsToPrint.forEach(System.out::print);
       System.out.println();
   }

   public static void main(String args[]) {
       // One object for two threads
       Printer printer  = new Printer();

       // Create two threads
       Writer1 writer1 = new Writer1(printer);
       Writer2 writer2 = new Writer2(printer);

       // Start them
       writer1.start();
       writer2.start();
   }
}

/**
* Author No. 1, who writes an original poem.
*/
class Writer1 extends Thread {
   Printer printer;

   Writer1(Printer printer) {
       this.printer = printer;
   }

   public void run() {
       List<string> poem = Arrays.asList("I ", this.getName(), " Write", " A Letter");
       printer.print(poem);
   }

}

/**
* Author No. 2, who writes an original poem.
*/
class Writer2 extends Thread {
   Printer printer;

   Writer2(Printer printer) {
       this.printer = printer;
   }

   public void run() {
       List<String> poem = Arrays.asList("I Do Not ", this.getName(), " Not Write", " No Letter");
       printer.print(poem);
   }
}
و خروجی کنسول این است:
I Thread-0 Write A Letter I Do Not Thread-1 Not Write No Letter

بلوک همگام سازی

یک بلوک همگام‌سازی شده می‌تواند برای انجام همگام‌سازی بر روی هر منبع خاص در یک روش استفاده شود. بیایید بگوییم که در یک روش بزرگ (بله، نباید آنها را بنویسید، اما گاهی اوقات اتفاق می افتد) به دلایلی فقط باید یک بخش کوچک را همگام کنید. اگر همه کدهای متد را در یک بلوک همگام‌سازی شده قرار دهید، مانند روش همگام‌سازی شده کار می‌کند. نحو به این صورت است:
synchronized ("object to be locked") {
   // The code that must be protected
}
برای جلوگیری از تکرار مثال قبلی، رشته هایی را با استفاده از کلاس های ناشناس ایجاد می کنیم، یعنی بلافاصله رابط Runnable را پیاده سازی می کنیم.
/**
* This is how a synchronization block is added.
* Inside the block, you need to specify which object's mutex will be acquired.
*/
class Printer {

   void print(List<String> wordsToPrint) {
       synchronized (this) {
           wordsToPrint.forEach(System.out::print);
       }
       System.out.println();
   }

   public static void main(String args[]) {
       // One object for two threads
       Printer printer = new Printer();

       // Create two threads
       Thread writer1 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I ", "Writer1", " Write", " A Letter");
               printer.print(poem);
           }
       });
       Thread writer2 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I Do Not ", "Writer2", " Not Write", " No Letter");
               printer.print(poem);
           }
       });

       // Start them
       writer1.start();
       writer2.start();
   }
}

}
و خروجی کنسول این است:
I Writer1 نامه می نویسم من نمی نویسم2 نامه نمی نویسم

همگام سازی استاتیک

اگر یک متد استاتیک را همگام سازی کنید، قفل در کلاس اتفاق می افتد، نه شی. در این مثال، ما همگام سازی استاتیک را با اعمال کلمه کلیدی همگام سازی شده در یک روش استاتیک انجام می دهیم:
/**
* This is how a synchronization block is added.
* Inside the block, you need to specify which object's mutex will be acquired.
*/
class Printer {

   static synchronized void print(List<String> wordsToPrint) {
       wordsToPrint.forEach(System.out::print);
       System.out.println();
   }

   public static void main(String args[]) {

       // Create two threads
       Thread writer1 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I ", "Writer1", " Write", " A Letter");
               Printer.print(poem);
           }
       });
       Thread writer2 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I Do Not ", "Writer2", " Not Write", " No Letter");
               Printer.print(poem);
           }
       });

       // Start them
       writer1.start();
       writer2.start();
   }
}
و خروجی کنسول این است:
I Do Not Writer2 Not Write No Letter I Writer1 Write A Letter

34. متغیر فرار چیست؟

در برنامه نویسی چند رشته ای، از کلمه کلیدی فرار برای ایمنی نخ استفاده می شود. هنگامی که یک متغیر قابل تغییر اصلاح می شود، تغییر برای همه رشته های دیگر قابل مشاهده است، بنابراین یک متغیر می تواند توسط یک رشته در یک زمان استفاده شود. با استفاده از کلمه کلیدی فرار ، می‌توانید تضمین کنید که یک متغیر از نظر موضوعی امن است و در حافظه مشترک ذخیره می‌شود و رشته‌ها آن را در حافظه پنهان خود ذخیره نمی‌کنند. این چگونه به نظر میرسد؟
private volatile AtomicInteger count;
ما فقط فرار را به متغیر اضافه می کنیم. اما به خاطر داشته باشید که این به معنای ایمنی کامل نخ نیست... از این گذشته، ممکن است عملیات روی متغیر اتمی نباشد. گفتنی است، می توانید از کلاس های Atomic که عملیات را به صورت اتمی انجام می دهند، یعنی در یک دستورالعمل واحد CPU استفاده کنید. از این قبیل کلاس ها در بسته java.util.concurrent.atomic بسیاری وجود دارد .

35. بن بست چیست؟

در جاوا بن بست چیزی است که می تواند به عنوان بخشی از multithreading اتفاق بیفتد. بن بست زمانی رخ می دهد که نخی منتظر قفل شی ای باشد که توسط نخ دیگری به دست می آید و نخ دوم منتظر قفل شی است که توسط نخ اول به دست می آید. این بدان معنی است که دو رشته در انتظار یکدیگر هستند و اجرای کد آنها نمی تواند ادامه یابد. 50 پرسش و پاسخ برتر مصاحبه شغلی برای Java Core.  قسمت 2 - 4بیایید مثالی را در نظر بگیریم که دارای کلاسی است که Runnable را پیاده سازی می کند. سازنده آن دو منبع می گیرد. متد run() به ترتیب قفل را برای آنها بدست می آورد. اگر دو شی از این کلاس ایجاد کنید، و منابع را به ترتیب متفاوتی ارسال کنید، به راحتی می توانید به بن بست برخورد کنید:
class DeadLock {

   public static void main(String[] args) {
       final Integer r1 = 10;
       final Integer r2 = 15;

       DeadlockThread threadR1R2 = new DeadlockThread(r1, r2);
       DeadlockThread threadR2R1 = new DeadlockThread(r2, r1);

       new Thread(threadR1R2).start();
       new Thread(threadR2R1).start();
   }
}

/**
* A class that accepts two resources.
*/
class DeadlockThread implements Runnable {

   private final Integer r1;
   private final Integer r2;

   public DeadlockThread(Integer r1, Integer r2) {
       this.r1 = r1;
       this.r2 = r2;
   }

   @Override
   public void run() {
       synchronized (r1) {
           System.out.println(Thread.currentThread().getName() + " acquired resource: " + r1);

           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }

           synchronized (r2) {
               System.out.println(Thread.currentThread().getName() + " acquired resource: " + r2);
           }
       }
   }
}
خروجی کنسول:
موضوع اول منبع اول را به دست آورد موضوع دوم منبع دوم را به دست آورد

36. چگونه از بن بست جلوگیری می کنید؟

از آنجایی که می دانیم بن بست چگونه رخ می دهد، می توانیم نتیجه گیری کنیم...
  • در مثال بالا، بن بست به دلیل این واقعیت است که ما قفل تودرتو داریم. یعنی ما یک بلوک همگام در داخل یک بلوک همگام داریم. برای جلوگیری از این امر، به جای تودرتو، باید یک لایه انتزاعی بالاتر جدید ایجاد کنید، همگام سازی را به سطح بالاتر منتقل کنید و قفل تودرتو را حذف کنید.
  • هرچه بیشتر قفل کنید، احتمال به بن بست رسیدن بیشتر می شود. بنابراین، هر بار که یک بلوک همگام‌سازی شده را اضافه می‌کنید، باید به این فکر کنید که آیا واقعاً به آن نیاز دارید و آیا می‌توانید از اضافه کردن بلوک جدید اجتناب کنید.
  • با استفاده از Thread.join() . شما همچنین می توانید در حالی که یک رشته منتظر موضوع دیگری است، به بن بست برخورد کنید. برای جلوگیری از این مشکل، ممکن است برای متد ()join یک بازه زمانی تعیین کنید .
  • اگر یک تاپیک داشته باشیم، دیگر بن بست وجود نخواهد داشت ;)

37. شرط نژاد چیست؟

اگر مسابقه‌های واقعی شامل ماشین‌ها می‌شود، پس مسابقه‌های چند رشته‌ای شامل رشته‌ها می‌شوند. اما چرا؟ :/ دو رشته در حال اجرا هستند و می توانند به یک شی دسترسی داشته باشند. و ممکن است همزمان سعی کنند وضعیت شی مشترک را به روز کنند. همه چیز تا اینجا روشن است، درست است؟ Thread ها یا به معنای واقعی کلمه به صورت موازی (اگر پردازنده بیش از یک هسته داشته باشد) یا به صورت متوالی اجرا می شوند، با پردازنده که برش های زمانی میان لایه را تخصیص می دهد. ما نمی توانیم این فرآیندها را مدیریت کنیم. این به این معنی است که وقتی یک رشته داده‌ها را از یک شی می‌خواند، نمی‌توانیم تضمین کنیم که قبل از اینکه رشته دیگری این کار را انجام دهد، زمان لازم را برای تغییر شی خواهد داشت. چنین مشکلاتی زمانی به وجود می آیند که ما این ترکیبات "بررسی و عمل" را داشته باشیم. معنی آن چیست؟ فرض کنید یک دستور if داریم که بدنه آن خود شرط if را تغییر می دهد، برای مثال:
int z = 0;

// Check
if (z < 5) {
// Act
   z = z + 5;
}
زمانی که z هنوز صفر است، دو رشته می‌توانند به طور همزمان وارد این بلوک کد شوند و سپس هر دو رشته می‌توانند مقدار آن را تغییر دهند. در نتیجه، مقدار مورد انتظار 5 را نخواهیم گرفت. در عوض، 10 را دریافت خواهیم کرد. چگونه از این امر جلوگیری می کنید؟ قبل از بررسی و اقدام باید یک قفل تهیه کنید و سپس قفل را آزاد کنید. یعنی باید اولین رشته را وارد بلوک if کنید ، تمام اقدامات را انجام دهید، z را تغییر دهید و تنها پس از آن به رشته بعدی این فرصت را بدهید تا همین کار را انجام دهد. اما رشته بعدی وارد بلوک if نمی شود ، زیرا z اکنون 5 خواهد بود:
// Acquire the lock for z
if (z < 5) {
   z = z + 5;
}
// Release z's lock
===================================================

به جای نتیجه گیری

می خواهم از همه کسانی که تا آخر خواندند تشکر کنم. راه درازی بود اما تو تحمل کردی! شاید همه چیز مشخص نباشد. این طبیعی است. وقتی برای اولین بار شروع به مطالعه جاوا کردم، نمی‌توانستم مغزم را در مورد متغیر ثابت بپیچم. اما چیز مهمی نیست. روی آن خوابیدم، چند منبع دیگر خواندم و بعد فهمیدم. آماده شدن برای مصاحبه بیشتر یک سوال آکادمیک است تا عملی. در نتیجه، قبل از هر مصاحبه، باید مواردی را که ممکن است زیاد استفاده نکنید مرور کرده و در حافظه خود تجدید کنید.

و مثل همیشه، در اینجا چند لینک مفید وجود دارد:

با تشکر از همه شما برای خواندن مطلب. به زودی می بینمت :) پروفایل GitHub من 50 پرسش و پاسخ برتر مصاحبه شغلی برای Java Core.  قسمت 2 - 5
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION