Синхронизация между потоками в Java важна, когда несколько потоков имеют доступ к общим ресурсам и должны обеспечивать безопасное взаимодействие. Java предоставляет механизмы синхронизации, такие как synchronized
блоки, мониторы, а также методы wait()
, notify()
, notifyAll()
и join()
для управления выполнением потоков.
1. wait()
, notify()
, notifyAll()
:
wait()
:
- Метод
wait()
вызывается внутриsynchronized
блока и передает монитор (блокировку), позволяя другим потокам использовать его. - Поток, вызвавший
wait()
, переходит в состояние ожидания до тех пор, пока другой поток не вызоветnotify()
илиnotifyAll()
на том же объекте.
notify()
:
- Метод
notify()
будит один из потоков, ожидающих на том же объекте. Выбранный поток зависит от планировщика потоков.
notifyAll()
:
- Метод
notifyAll()
будит все потоки, ожидающие на том же объекте.
Пример использования:
java
class SharedResource { boolean flag = false; synchronized void printNumbers() { while (!flag) { try { wait(); // Поток ожидает, пока другой поток не вызовет notify() } catch (InterruptedException e) { e.printStackTrace(); } } // Логика вывода чисел System.out.println("1"); System.out.println("2"); System.out.println("3"); flag = false; notify(); // Уведомление другого потока } synchronized void printLetters() { while (flag) { try { wait(); // Поток ожидает, пока другой поток не вызовет notify() } catch (InterruptedException e) { e.printStackTrace(); } } // Логика вывода букв System.out.println("A"); System.out.println("B"); System.out.println("C"); flag = true; notify(); // Уведомление другого потока } } public class Main { public static void main(String[] args) { SharedResource sharedResource = new SharedResource(); Thread t1 = new Thread(() -> { for (int i = 0; i < 5; i++) { sharedResource.printNumbers(); } }); Thread t2 = new Thread(() -> { for (int i = 0; i < 5; i++) { sharedResource.printLetters(); } }); t1.start(); t2.start(); } }
2. join()
:
Метод join()
применяется для ожидания завершения другого потока. Текущий поток будет ожидать завершения потока, для которого вызывается join()
.
Пример использования:
java
public class JoinExample { public static void main(String[] args) { Thread t1 = new Thread(() -> { for (int i = 1; i <= 5; i++) { System.out.println("Thread 1 - Count: " + i); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread t2 = new Thread(() -> { for (int i = 1; i <= 5; i++) { System.out.println("Thread 2 - Count: " + i); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } }); t1.start(); try { t1.join(); // Ожидание завершения t1 } catch (InterruptedException e) { e.printStackTrace(); } t2.start(); } }
В этом примере, после вызова t1.join()
, программа будет ждать завершения потока t1
, прежде чем продолжить выполнение.