The

„Здрасти, Амиго!“

„Искам да се потопя дълбоко с вас по отношение на изчакване-уведомяване. Методите за изчакване-уведомяване осигуряват удобен механизъм за взаимодействие на нишки. Те могат също да се използват за изграждане на сложни механизми на високо ниво за взаимодействие на нишки.“

„Ще започна с малък пример. Да предположим, че имаме програма за сървър, който трябва да изпълнява различни задачи, създадени от потребители чрез уебсайт. Потребителите могат да добавят различни задачи по различно време. Задачите са ресурсоемки, но 8 на нашия сървър -ядрен процесор може да се справи. Как трябва да изпълняваме задачите на сървъра?"

„Първо, ще създадем група от работни нишки, толкова, колкото има процесорни ядра. Всяка нишка ще може да работи на собственото си ядро: нишките няма да си пречат една на друга и процесорните ядра няма седи без работа."

„Второ, ще създадем обект на опашка, където ще се добавят задачите на потребителите. Различни типове задачи ще съответстват на различни обекти, но всички те ще имплементират интерфейса Runnable, така че да могат да се изпълняват.“

„Бихте ли ми дали пример за обект на задача?“

"Виж това:"

Клас, който изчислява n факториел, когато се извика методът run().
class Factorial implements Runnable
{
 public int n = 0;
 public long result = 1;

 public Factorial (int n)
 {
  this.n = n;
 }

 public void run()
 {
  for (int i = 2; i <= n; i++)
   result *= i;
 }
}

"Дотук добре."

„Страхотно. Тогава нека разгледаме How трябва да изглежда един обект на опашка. Какво можете да ми кажете за него?“

„Тя трябва да е безопасна за нишки. Зарежда се с обекти на задачи от нишка, която ги получава от потребителите, а след това задачите се взимат от работни нишки.“

„Да. И Howво ще стане, ако ни свършат задачите за известно време?“

„Тогава работните нишки трябва да изчакат, докато има повече.“

„Точно така. Сега си представете, че всичко това може да бъде изградено в една опашка. Вижте го:“

Опашка от задачи. Ако няма задачи, тогава нишката заспива и чака да се появи една:
public class JobQueue
{
 ArrayList jobs = new ArrayList();

 public synchronized void put(Runnable job)
 {
  jobs.add(job);
  this.notifyAll();
 }

 public synchronized Runnable getJob()
 {
  while (jobs.size() == 0)
   this.wait();

  return jobs.remove(0);
 }
}

"Имаме метод getJob , който проверява дали списъкът със задачи е празен. След това нишката заспива (изчаква), докато нещо се появи в списъка."

„Има и методът put , който ви позволява да добавите нова задача към списъка. Веднага щом се добави нова задача, се извиква методът notifyAll . Извикването на този метод събужда всички работни нишки, които са заспали в метода getJob.“

„Можете ли да си спомните отново How работят методите за изчакване и уведомяване?“

„Методът за изчакване се извиква само вътре в синхронизиран блок, на mutex обект. В нашия случай: това. Освен това се случват две неща:

1) Конецът заспива.

2) Нишката временно освобождава mutex (докато се събуди).

„След това други нишки могат да влязат в синхронизирания блок и да придобият същия мутекс.“

" Методът notifyAll също може да бъде извикан само вътре в синхронизирания блок на mutex обект. В нашия случай: това. Освен това се случват две неща:"

1) Всички нишки, които чакат този mutex обект, се събуждат.

2) След като текущата нишка излезе от синхронизирания блок, една от събудените нишки придобива mutex и продължава работата си. Когато освободи мутекса, друга пробудена нишка придобива мутекса и т.н.

„Много прorча на автобус. Влизаш и искаш да си платиш билета, но няма шофьор. Така че „заспиваш“. В крайна сметка автобусът е опакован, но все още няма на кого да дадеш билета. Тогава шофьорът пристига и казва: «Фар, моля». И това е началото на..."

"Интересно сравнение. Но Howво е автобус?"

„Хулио обясни това. Имаше тези странни неща, използвани в 21-ви век.“