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

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

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

Из-за неполной синхронизации потоков было заметно, что очередность вывода нарушается. Происходит это потому, что переключение между потоками происходит быстрее, чем выполняется цикл (у нас там внутри цикла еще и задержка в 5мс.), поэтому пока один поток выполняет одну - две итерации цикла, второй поток тоже успевает воспользоваться ресурсом один или два раза подряд.

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

Для использования синхронизации, нужно заключить ресурсную часть кода и сам блокируемый ресурс в специальный оператор: 

 synchronized(ресурс) { код_с_доступом_к_ресурсу }

 Переделаем программу так, чтобы включить ресурсную часть кода в оператор синхронизации:

static class Print_scr {

     public Print_scr() {  }   // конструктор класса

       public void print(String str) { 

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

       }   }

 static class MyThread implements Runnable {

       private String str;

       private Print_scr sc;

            MyThread(String s, Print_scr p) {

               str = s; sc = p;

       }

             public void run() {

           synchronized(sc){

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

                                               try {

                                               Thread.sleep(5);

                                    } catch (InterruptedException e) { }

                                                     sc.print(str + " ");

                            

               //System.out.print(str + " ");   // прежний способ вывода отключен

               }

           System.out.print(" ");

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

           }

           }

   }

 public static void main(String[] args) {

               Print_scr sc = new Print_scr();

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

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

 }

 В данном случае мы специально создали некий класс  Print_scr, который делает вывод на экран с помошью своей функции print(String str). Доступ к этому классу является ресурсным и ссылку на него мы передаем внутрь создаваемого потока через его конструктор. Блок кода с циклом for мы заключили в оператор синхронизации и пометили, что доступ к объекту sc является ресурсным, поместив его в круглые скобки оператора synchronized:

 synchronized(sc){

for …

}

  Теперь пока в одном потоке не отработает цикл for, другой поток не сможет завладеть объектом sc, чтобы осуществить вывод на экран.

Как и следовало ожидать, после запуска, программа напечатает:

 1  1  1  1  1  1  1  1  1  1   

2  2  2  2  2  2  2  2  2  2

 То есть, теперь потоки отрабатывают вывод на экран строго последовательно, один за другим.