Перейти к контенту

Синхронизация потоков в Java через оператор synchronized

Когда мы запускаем два или более потоков в программе, может возникнуть ситуация, когда несколько потоков пытаются получить доступ к одному и тому же ресурсу, и, наконец, они могут привести к непредвиденному результату из-за проблем параллелизма.

Например, если несколько потоков пытаются выполнить запись в одном и том же файле, они могут повредить данные, потому что один из потоков может переопределить данные, или когда один поток открывает один и тот же файл в то же время, другой поток может закрывать тот же файл.

 

Таким образом, необходимо синхронизировать действие нескольких потоков и убедиться, что только один поток может получить доступ к ресурсу в данный момент времени. Это реализовано с использованием концепции, называемой мониторами. Каждый объект в Java связан с монитором, который поток может заблокировать или разблокировать. Только один поток за раз может удерживать блокировку на мониторе.

Язык программирования Java предоставляет очень удобный способ создания потоков и синхронизации их задач с помощью синхронизированных блоков. Вы храните общие ресурсы в этом блоке. Ниже приводится общая форма синхронизированного оператора в Java —

Синтаксис оператора synchronized

synchronized(objectidentifier) {
   // Access shared variables and other shared resources
}

Здесь, objectidentifier является ссылкой на объект, чья блокировка связана с монитором, который представляет синхронизированный оператор. Теперь мы увидим два примера, где мы напечатаем счетчик с использованием двух разных потоков.

Когда потоки не синхронизированы, они печатают значение счетчика, которое не в последовательности, но когда мы печатаем счетчик, помещая внутрь блока synchronized(), тогда он печатает счетчик очень последовательно для обоих потоков.

Пример многопоточности без синхронизации

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

class PrintDemo {
   public void printCount() {
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println("Counter   ---   "  + i );
         }
      } catch (Exception e) {
         System.out.println("Thread  interrupted.");
      }
   }
}
class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   PrintDemo  PD;

   ThreadDemo( String name,  PrintDemo pd) {
      threadName = name;
      PD = pd;
   }
   
   public void run() {
      PD.printCount();
      System.out.println("Thread " +  threadName + " exiting.");
   }

   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {
   public static void main(String args[]) {
      PrintDemo PD = new PrintDemo();

      ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD );
      ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD );

      T1.start();
      T2.start();

      // wait for threads to end
         try {
         T1.join();
         T2.join();
      } catch ( Exception e) {
         System.out.println("Interrupted");
      }
   }
}

Это приводит к другому результату каждый раз, когда вы запускаете эту программу —

Итог

Starting Thread - 1
Starting Thread - 2
Counter   ---   5
Counter   ---   4
Counter   ---   3
Counter   ---   5
Counter   ---   2
Counter   ---   1
Counter   ---   4
Thread Thread - 1  exiting.
Counter   ---   3
Counter   ---   2
Counter   ---   1
Thread Thread - 2  exiting.

Пример многопоточности с синхронизацией

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

class PrintDemo {
   public void printCount() {
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println("Counter   ---   "  + i );
         }
      } catch (Exception e) {
         System.out.println("Thread  interrupted.");
      }
   }
}

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   PrintDemo  PD;

   ThreadDemo( String name,  PrintDemo pd) {
      threadName = name;
      PD = pd;
   }
   
   public void run() {
      synchronized(PD) {
         PD.printCount();
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }

   public void start () {
      System.out.println("Starting " +  threadName );
      
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {
   public static void main(String args[]) {
      PrintDemo PD = new PrintDemo();

      ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD );
      ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD );

      T1.start();
      T2.start();

      // wait for threads to end
      try {
         T1.join();
         T2.join();
      } catch ( Exception e) {
         System.out.println("Interrupted");
      }
   }
}

Это дает тот же результат каждый раз, когда вы запускаете эту программу —

Итог

Starting Thread - 1
Starting Thread - 2
Counter   ---   5
Counter   ---   4
Counter   ---   3
Counter   ---   2
Counter   ---   1
Thread Thread - 1  exiting.
Counter   ---   5
Counter   ---   4
Counter   ---   3
Counter   ---   2
Counter   ---   1
Thread Thread - 2  exiting.

Оцени статью

Средняя оценка / 5. Количество голосов:

Спасибо, помогите другим - напишите комментарий, добавьте информации к статье.

Или поделись статьей

Видим, что вы не нашли ответ на свой вопрос.

Помогите улучшить статью.

 

Пока нет комментариев.

Добавить комментарий

Ваш e-mail не будет опубликован.

СайдбарКомментарии (0)