JavaRush /وبلاگ جاوا /Random-FA /50 پرسش و پاسخ اصلی مصاحبه اصلی جاوا. قسمت 3
Roman Beekeeper
مرحله

50 پرسش و پاسخ اصلی مصاحبه اصلی جاوا. قسمت 3

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

چند رشته ای

37. چگونه یک رشته (جریان) جدید در جاوا ایجاد کنیم؟

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

ما از کلاس Thread ارث می بریم

برای ساخت این کار، در کلاس ما از java.lang.Thread. این حاوی متد است run()که دقیقاً همان چیزی است که ما به آن نیاز داریم. تمام عمر و منطق تاپیک جدید در این روش خواهد بود. این یک نوع mainروش برای یک موضوع جدید است. پس از این، تنها چیزی که باقی می ماند این است که یک شی از کلاس خود ایجاد کنیم و متد را اجرا کنیم start()، که یک رشته جدید ایجاد می کند و منطق نوشته شده در آن را اجرا می کند. بیایید نگاه بیندازیم:
/**
* Пример того, How создавать треды путем наследования {@link Thread} класса.
*/
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. به نظر می رسد که خطوط بیشتر بدتر هستند. اما می دانیم که ارث چقدر مضر است و بهتر است به هر طریقی از آن اجتناب کنیم ;) بیایید نگاه کنیم:
/**
* Пример того, How создавать треды из интерфейса {@link Runnable}.
* Здесь проще простого - реализуем этот интерфейс и потом передаем в конструктор
* экземпляр реализуемого an object.
*/
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

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

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

39- مزایای چند رشته ای چیست؟

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

40. در چرخه حیات نخ چه حالاتی وجود دارد؟

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

41. آیا می توان یک تاپیک را دو بار راه اندازی کرد؟

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

   /**
    * Имитируем работу треда
    */
   public void run() {
	// что-то происходит. Для нас не существенно на этом этапе
   }

   /**
    * Запускаем тред дважды
    */
   public static void main(String[] args) {
       DoubleStartThreadExample doubleStartThreadExample = new DoubleStartThreadExample();
       doubleStartThreadExample.start();
       doubleStartThreadExample.start();
   }
}
به محض اینکه کار به شروع دوم همان تاپیک برسد، یک استثنا وجود خواهد داشت. خودتان امتحان کنید؛) یک بار دیدن بهتر از صد بار شنیدن است.

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

بله، run()مطمئناً می توانید یک متد را فراخوانی کنید، اما با این کار یک رشته جدید ایجاد نمی شود و آن را به عنوان یک موضوع جداگانه اجرا نمی کنید. در این مورد، یک شی ساده است که یک متد ساده را فراخوانی می کند. اگر در مورد روش صحبت می کنیم start()، آنگاه موضوع متفاوت است. با راه‌اندازی این روش، runtimeروش جدیدی را راه‌اندازی می‌کند و به نوبه خود، روش ما را اجرا می‌کند؛) اگر به من باور ندارید، آن را امتحان کنید:
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();

       // просто будут вызваны в потоке main два метода, один за другим.
       runExample1.run();
       runExample2.run();
   }
}
و خروجی کنسول به این صورت خواهد بود:

0123401234
مشاهده می شود که هیچ موضوعی ایجاد نشده است. همه چیز مثل یک کلاس معمولی کار می کرد. ابتدا روش کلاس اول کار کرد، سپس روش دوم.

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

50 پرسش و پاسخ اصلی مصاحبه اصلی جاوا.  قسمت 3 - 4رشته دیمون (که از این پس به عنوان نخ شبح نامیده می‌شود) رشته‌ای است که وظایفی را در پس‌زمینه در رابطه با رشته‌ای دیگر انجام می‌دهد. یعنی وظیفه آن انجام کارهای کمکی است که فقط باید در ارتباط با رشته (اصلی) دیگری انجام شوند. بسیاری از موضوعات شبح وجود دارند که به طور خودکار کار می کنند، مانند Garbage Collector، finalizer و غیره.

چرا جاوا موضوع دیمون را می بندد؟

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

روش های کار در کلاس Thread

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

   public void run() {
       // Проверяет, демон ли этот поток or нет
       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();

       // теперь thread1 - поток-демон.
       thread1.setDaemon(true);

       System.out.println("демон?.. " + thread1.isDaemon());
       System.out.println("демон?.. " + thread2.isDaemon());
       System.out.println("демон?.. " + thread3.isDaemon());

       thread1.start();
       thread2.start();
       thread3.start();
   }
}
خروجی کنسول:

демон?.. true
демон?.. false
демон?.. false
daemon thread
user thread
user thread
از خروجی می بینیم که در داخل خود thread با استفاده از currentThread()روش ایستا می توانیم بفهمیم که از یک طرف کدام نخ است، از طرف دیگر اگر به موضوع این thread ارجاع داشته باشیم می توانیم بفهمیم. مستقیما از آن این انعطاف پذیری لازم را در پیکربندی می دهد.

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

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

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

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

       // здесь будет выброшено исключение
       afterStartExample.setDaemon(true);
   }
}
خروجی کنسول:

Working...
Exception in thread "main" java.lang.IllegalThreadStateException
	at java.lang.Thread.setDaemon(Thread.java:1359)
	at SetDaemonAfterStartExample.main(SetDaemonAfterStartExample.java:14)

45. shutdownhook چیست؟

Shutdownhook یک رشته است که به طور ضمنی قبل از خاموش شدن JVM (ماشین مجازی جاوا) فراخوانی می شود. بنابراین وقتی ماشین مجازی جاوا به طور عادی یا ناگهانی خاموش می شود، می توانیم از آن برای پاکسازی یک منبع یا ذخیره وضعیت استفاده کنیم. می توانیم shutdown hookبا استفاده از روش زیر اضافه کنیم:
Runtime.getRuntime().addShutdownHook(new ShutdownHookThreadExample());
همانطور که در مثال نشان داده شده است:
/**
* Программа, которая показывает How запустить shutdown hook тред,
* который выполнится аккурат до окончания работы JVM
*/
class ShutdownHookThreadExample extends Thread {

   public void run() {
       System.out.println("shutdown hook задачу выполнил");
   }

   public static void main(String[] args) {

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

       System.out.println("Теперь программа засыпает, нажмите ctrl+c чтоб завершить ее.");
       try {
           Thread.sleep(60000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
   }
}
خروجی کنسول:

Теперь программа засыпает, нажмите ctrl+c чтоб завершить ее.
shutdown hook задачу выполнил

46. ​​همگام سازی چیست؟

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

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

روش همگام سازی شده برای قفل کردن یک شی برای هر منبع مشترک استفاده می شود. هنگامی که یک رشته یک متد هماهنگ شده را فراخوانی می کند، به طور خودکار روی آن شی قفل می گیرد و زمانی که رشته کار خود را کامل می کند، آن را آزاد می کند. برای اینکه کار کند، باید کلمه کلیدی همگام شده را اضافه کنید . بیایید ببینیم که چگونه با یک مثال کار می کند:
/**
* Пример, где мы синхронизируем метод. То есть добавляем ему слово synchronized.
* Есть два писателя, которые хотят использовать один принтер. Они подготовor свои поэмы
* И конечно же не хотят, чтоб их поэмы перемешались, а хотят, чтоб работа была сделана по * * * очереди для каждого из них
*/
class Printer {

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

   public static void main(String args[]) {
       // один an object для двух тредов
       Printer printer  = new Printer();

       // создаем два треда
       Writer1 writer1 = new Writer1(printer);
       Writer2 writer2 = new Writer2(printer);

       // запускаем их
       writer1.start();
       writer2.start();
   }
}

/**
* Писатель номер 1, который пишет свою поэму.
*/
class Writer1 extends Thread {
   Printer printer;

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

   public void run() {
       List<string> poem = Arrays.asList("Я ", this.getName(), " Пишу", " Письмо");
       printer.print(poem);
   }

}

/**
* Писатель номер 2, который пишет свою поэму.
*/
class Writer2 extends Thread {
   Printer printer;

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

   public void run() {
       List<String> poem = Arrays.asList("Не Я ", this.getName(), " Не пишу", " Не Письмо");
       printer.print(poem);
   }
}
و خروجی کنسول:

Я Thread-0 Пишу Письмо
Не Я Thread-1 Не пишу Не Письмо

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

یک بلوک همگام‌سازی شده می‌تواند برای انجام همگام‌سازی بر روی هر منبع روش خاصی استفاده شود. بیایید بگوییم که در یک روش بزرگ (بله، بله، شما نمی توانید چنین چیزهایی را بنویسید، اما گاهی اوقات این اتفاق می افتد) به دلایلی فقط باید یک قسمت کوچک را همگام کنید. اگر تمام کدهای یک متد را در یک بلوک همگام‌سازی شده قرار دهید، مانند روش همگام‌سازی شده عمل می‌کند. نحو به این شکل است:
synchronized (“an object для блокировки”) {
   // сам code, который нужно защитить
}
برای اینکه مثال قبلی را تکرار نکنیم، رشته هایی را از طریق کلاس های ناشناس ایجاد می کنیم - یعنی بلافاصله رابط Runnable را پیاده سازی می کنیم.
/**
* Вот How добавляется блок синхронизации.
* Внутри нужно указать у кого будет взят мьютекс для блокировки.
*/
class Printer {

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

   public static void main(String args[]) {
       // один an object для двух тредов
       Printer printer = new Printer();

       // создаем два треда
       Thread writer1 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("Я ", "Writer1", " Пишу", " Письмо");
               printer.print(poem);
           }
       });
       Thread writer2 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("Не Я ", "Writer2", " Не пишу", " Не Письмо");
               printer.print(poem);
           }
       });

       // запускаем их
       writer1.start();
       writer2.start();
   }
}

}
و خروجی به کنسول

Я Writer1 Пишу Письмо
Не Я Writer2 Не пишу Не Письмо

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

اگر یک روش استاتیک را همگام سازی کنید، قفل روی کلاس خواهد بود، نه روی شی. در این مثال، کلمه کلیدی همگام‌سازی شده را به یک روش ثابت برای انجام همگام‌سازی استاتیک اعمال می‌کنیم:
/**
* Вот How добавляется блок синхронизации.
* Внутри нужно указать у кого будет взят мьютекс для блокировки.
*/
class Printer {

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

   public static void main(String args[]) {

       // создаем два треда
       Thread writer1 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("Я ", "Writer1", " Пишу", " Письмо");
               Printer.print(poem);
           }
       });
       Thread writer2 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("Не Я ", "Writer2", " Не пишу", " Не Письмо");
               Printer.print(poem);
           }
       });

       // запускаем их
       writer1.start();
       writer2.start();
   }
}
و خروجی کنسول:

Не Я Writer2 Не пишу Не Письмо
Я Writer1 Пишу Письмо

47- متغیر فرار چیست؟

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

48. بن بست چیست

بن بست در جاوا بخشی از multithreading است. بن بست می تواند در شرایطی اتفاق بیفتد که یک نخ در انتظار یک قفل شی که توسط نخ دیگری به دست آمده است، و یک نخ دوم در انتظار یک قفل شی که توسط نخ اول به دست آمده است، باشد. بنابراین، این دو رشته در انتظار یکدیگر می مانند و به اجرای کد خود ادامه نمی دهند. 50 پرسش و پاسخ اصلی مصاحبه اصلی جاوا.  قسمت 3 - 5بیایید به مثالی نگاه کنیم که در آن کلاسی وجود دارد که 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();
   }
}

/**
* Класс, который принимает два ресурса.
*/
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() + " захватил ресурс: " + r1);

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

           synchronized (r2) {
               System.out.println(Thread.currentThread().getName() + " захватил ресурс: " + r2);
           }
       }
   }
}
خروجی کنسول:

Первый тред захватил первый ресурс
Второй тред захватывает второй ресурс

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

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

50. شرط مسابقه چیست؟

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

// проверь
if (z < 5) {
//действуй
   z = z + 5;
}
بنابراین ممکن است شرایطی پیش بیاید که در زمانی که z هنوز برابر با صفر است، دو رشته به طور همزمان وارد این بلوک کد شوند و با هم این مقدار را تغییر دهند. و در پایان ما مقدار مورد انتظار 5 را بدست نمی آوریم، بلکه 10 را دریافت خواهیم کرد. چگونه از این امر جلوگیری کنیم؟ قبل و بعد از اجرا باید قفل کنید. یعنی برای اینکه اولین رشته وارد بلوک شود if، تمام اقدامات را انجام دهید، آن را تغییر دهید zو تنها پس از آن به رشته بعدی فرصت دهید تا این کار را انجام دهد. اما موضوع بعدی وارد بلوک نمی شود if، زیرا zقبلاً برابر با 5 خواهد بود:
// получить блокировку для z
if (z < 5) {
   z = z + 5;
}
// выпустить из блокировки z
===================================================

به جای خروجی

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

و مثل همیشه لینک های مفید:

از همه شما برای خواندن متشکرم، به زودی شما را می بینیم) نمایه من در GitHub
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION