Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
кпп.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
238.24 Кб
Скачать

Синхронизация потоков с помощью семафоров.

В примере выше мы рассматривали вариант тотальной блокировки ресурса, когда ресурс оставался блокированным, пока один из потоков полностью не закончит с ним работу. Но что делать, если нам не нужно, чтобы поток блокировал ресурс на длительное время? Что если мы хотим заставить потоки выкидывать данные на экран строго по очереди?

Что если мы не хотим, чтобы ресурс блокировался монопольно? Что, если нам достаточно, чтобы с ресурсом в каждый момент времени работало ограниченное число потоков? Скажем, штук 5 и не больше?

Здесь нам на помощь придут специальные конструкции языка, называемые семафорами.

 Механизм, который используется в большинстве современных ОС для подобной синхронизации потоков, называется семафор. Принцип действия основан на временном монопольном блокировании потоком какого-либа ресурса и ограничении доступа всех остальных потоков к нему до тех пор, пока он ему нужен. Похоже на действие семафора, который блокирует трафик на перекрестке, пуская пересекающиеся потоки машин с разных направлений строго по очереди. При этом, продолжительность блокирования ресурса и освобождение его определяется самим потоком.

Изменим программу таким образом, чтобы использовать семафоры.

 static class Print_scr {

       int x = 1;

            public Print_scr() {  }

      public void print(String str) {

           System.out.print(str + " ");

       }

    }

     static class MyThread implements Runnable {

       private String str;

       private Print_scr ps;

       private Semaphore sm;

             MyThread(String s, Semaphore sem, Print_scr p) {

               str = s; ps = p; sm = sem;

       }

             public void run() {

                  for(int i = 0; i < 10; i++) {

                          try {

                   sm.acquire();

                                     if(ps.x == Integer.parseInt(str)) {

                        ps.print(str + " ");

                            if(Integer.parseInt(str) == 1) ps.x = 2;

                            if(Integer.parseInt(str) == 2) ps.x = 1;

                   }

                   sm.release();

                   Thread.sleep(5);

               } catch (InterruptedException e) {}

                           }

           System.out.print(" \n");

           }

   }

      public static void main(String[] args) {

       

       Semaphore sem  =  new Semaphore(1);  // создаем семафор с 1 разрешением

        Print_scr sc = new Print_scr();

              new Thread(new MyThread("1", sem, sc), "T1").start();

       new Thread(new MyThread("2", sem, sc), "T1").start();

     }

 Здесь мы добавили в класс Print_scr специальное поле int x, которое определяет какой поток в данное время может воспользоваться ресурсом. Далее мы изменили класс MyThread, добавив в него переменную, которая будет содержать наш семафор, кроме того мы встроили блок, который будет проверять состояние переменной ps.x  и  переключать состояние этой переменной. Функция sm.acquire()  определяет состояние семафора и если он открыт, захватывает его. Функция sm.release() освобождает семафор, когда он больше не нужен. Ну и в заключение, в функции main() мы создаем экземпляр семафора и передаем этот экземпляр внутрь классов потоков. Обратите внимание, что сигнатуру вызова конструктора класса потока мы тоже доработали, чтобы он принимал ссылку на объект семафора. Кстати, семафор, который имеет разрешение только на один поток (как у нас здесь), в терминологии многопоточного программирования называется "мъютекс".

В итоге на экране будет напечатано:

  1. 2  1  2  1  2  1  2  1  2  1  2  1  2  1  2  1  2