Использование synchronized в многопоточности
Ключевое слово synchronized в Java используется для управления доступом к общим ресурсам несколькими потоками. Оно обеспечивает, что только один поток может выполнить синхронизированный блок или метод в определенный момент времени, предотвращая состояние гонки и обеспечивая корректное выполнение многопоточных программ.
Синхронизированные методы
Синхронизированные методы автоматически захватывают монитор объекта, на котором они вызываются. Это гарантирует, что только один поток может выполнить синхронизированный метод объекта одновременно.
Синхронизированные блоки
Синхронизированные блоки позволяют синхронизировать доступ к общим ресурсам более гибко, чем синхронизированные методы. Они позволяют выбрать объект для захвата монитора и синхронизировать только часть кода, что может повысить производительность.
Синхронизация по классу
Синхронизация по классу используется для статических методов и блоков. В этом случае захватывается монитор класса, а не объекта.
Ключевое слово synchronized в Java используется для управления доступом к общим ресурсам несколькими потоками. Оно обеспечивает, что только один поток может выполнить синхронизированный блок или метод в определенный момент времени, предотвращая состояние гонки и обеспечивая корректное выполнение многопоточных программ.
Синхронизированные методы
Синхронизированные методы автоматически захватывают монитор объекта, на котором они вызываются. Это гарантирует, что только один поток может выполнить синхронизированный метод объекта одновременно.
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
public class MyThread extends Thread {
private Counter counter;
public MyThread(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
}
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
MyThread thread1 = new MyThread(counter);
MyThread thread2 = new MyThread(counter);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("Final count: " + counter.getCount()); // 2000
}
}
Синхронизированные блоки
Синхронизированные блоки позволяют синхронизировать доступ к общим ресурсам более гибко, чем синхронизированные методы. Они позволяют выбрать объект для захвата монитора и синхронизировать только часть кода, что может повысить производительность.
public class Counter {
private int count = 0;
private final Object lock = new Object();
public void increment() {
synchronized (lock) {
count++;
}
}
public int getCount() {
synchronized (lock) {
return count;
}
}
}
public class MyThread extends Thread {
private Counter counter;
public MyThread(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
}
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
MyThread thread1 = new MyThread(counter);
MyThread thread2 = new MyThread(counter);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("Final count: " + counter.getCount()); // 2000
}
}
Синхронизация по классу
Синхронизация по классу используется для статических методов и блоков. В этом случае захватывается монитор класса, а не объекта.
public class StaticCounter {
private static int count = 0;
public static synchronized void increment() {
count++;
}
public static synchronized int getCount() {
return count;
}
}
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
StaticCounter.increment();
}
}
public static void main(String[] args) throws InterruptedException {
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("Final count: " + StaticCounter.getCount()); // 2000
}
}
Mutex и Lock
В Java Lock предоставляется в пакете java.util.concurrent.locks. Это более мощный инструмент синхронизации, чем synchronized, предлагающий больше возможностей, таких как попытка захвата блокировки без ожидания, прерывание во время ожидания блокировки и использование условных переменных.
Интерфейс Lock
Интерфейс Lock предоставляет основные методы для управления блокировкой.
lock(): Захватывает блокировку.
unlock(): Освобождает блокировку.
tryLock(): Попытка захвата блокировки без ожидания.
lockInterruptibly(): Захват блокировки с возможностью прерывания.
Пример использования ReentrantLock
ReentrantLock — это реализация интерфейса Lock, позволяющая потоку захватить блокировку несколько раз.
Использование tryLock()
Метод tryLock() пытается захватить блокировку немедленно, возвращая true, если это удалось, и false в противном случае.
В Java Lock предоставляется в пакете java.util.concurrent.locks. Это более мощный инструмент синхронизации, чем synchronized, предлагающий больше возможностей, таких как попытка захвата блокировки без ожидания, прерывание во время ожидания блокировки и использование условных переменных.
Интерфейс Lock
Интерфейс Lock предоставляет основные методы для управления блокировкой.
lock(): Захватывает блокировку.
unlock(): Освобождает блокировку.
tryLock(): Попытка захвата блокировки без ожидания.
lockInterruptibly(): Захват блокировки с возможностью прерывания.
Пример использования ReentrantLock
ReentrantLock — это реализация интерфейса Lock, позволяющая потоку захватить блокировку несколько раз.
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private int count = 0;
private final Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
}
public class MyThread extends Thread {
private Counter counter;
public MyThread(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
}
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
MyThread thread1 = new MyThread(counter);
MyThread thread2 = new MyThread(counter);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("Final count: " + counter.getCount()); // 2000
}
}
Использование tryLock()
Метод tryLock() пытается захватить блокировку немедленно, возвращая true, если это удалось, и false в противном случае.
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private int count = 0;
private final Lock lock = new ReentrantLock();
public void increment() {
if (lock.tryLock()) {
try {
count++;
} finally {
lock.unlock();
}
} else {
System.out.println("Unable to lock");
}
}
public int getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
}
public class MyThread extends Thread {
private Counter counter;
public MyThread(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
}
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
MyThread thread1 = new MyThread(counter);
MyThread thread2 = new MyThread(counter);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("Final count: " + counter.getCount()); // 2000
}
}
Условные переменные
Condition — это интерфейс, предоставляющий средства для блокировки потоков до тех пор, пока они не будут сигнализировать другим потокам. Это более гибкая альтернатива методу wait() и notify() в синхронизированных блоках.
#Java #Training #Multithreading #Medium
Condition — это интерфейс, предоставляющий средства для блокировки потоков до тех пор, пока они не будут сигнализировать другим потокам. Это более гибкая альтернатива методу wait() и notify() в синхронизированных блоках.
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BoundedBuffer {
private final Lock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
private final Object[] items = new Object[100];
private int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length) {
notFull.await();
}
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
count++;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
notEmpty.await();
}
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
count--;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
#Java #Training #Multithreading #Medium
Многопоточность в Java: wait и notify
В Java методы wait(), notify(), и notifyAll() используются для управления потоками в многопоточной среде. Они позволяют потокам координировать свои действия при доступе к общим ресурсам, предоставляя механизм для ожидания и уведомления. Эти методы определены в классе Object и должны вызываться из синхронизированного контекста.
Метод wait()
Метод wait() заставляет текущий поток ждать до тех пор, пока другой поток не вызовет метод notify() или notifyAll() для этого объекта. Поток, вызвавший wait(), освобождает монитор и переходит в состояние ожидания.
Пример использования wait():
Метод notify()
Метод notify() пробуждает один из потоков, ожидающих этого объекта. Выбор потока, который будет пробужден, не определяется, поэтому для пробуждения всех ожидающих потоков используется метод notifyAll().
Пример использования notify():
#Java #Training #Multithreading #Medium
В Java методы wait(), notify(), и notifyAll() используются для управления потоками в многопоточной среде. Они позволяют потокам координировать свои действия при доступе к общим ресурсам, предоставляя механизм для ожидания и уведомления. Эти методы определены в классе Object и должны вызываться из синхронизированного контекста.
Метод wait()
Метод wait() заставляет текущий поток ждать до тех пор, пока другой поток не вызовет метод notify() или notifyAll() для этого объекта. Поток, вызвавший wait(), освобождает монитор и переходит в состояние ожидания.
Пример использования wait():
public class WaitNotifyExample {
private final Object lock = new Object();
private boolean condition = false;
public void doWait() {
synchronized (lock) {
while (!condition) {
try {
System.out.println("Waiting...");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Condition met!");
}
}
public void doNotify() {
synchronized (lock) {
condition = true;
lock.notify();
System.out.println("Notified!");
}
}
public static void main(String[] args) {
WaitNotifyExample example = new WaitNotifyExample();
Thread waiter = new Thread(example::doWait);
Thread notifier = new Thread(example::doNotify);
waiter.start();
try {
Thread.sleep(1000); // Задержка для демонстрации ожидания
} catch (InterruptedException e) {
e.printStackTrace();
}
notifier.start();
}
}
Метод notify()
Метод notify() пробуждает один из потоков, ожидающих этого объекта. Выбор потока, который будет пробужден, не определяется, поэтому для пробуждения всех ожидающих потоков используется метод notifyAll().
Пример использования notify():
public class WaitNotifyExample {
private final Object lock = new Object();
private boolean condition = false;
public void doWait() {
synchronized (lock) {
while (!condition) {
try {
System.out.println("Waiting...");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Condition met!");
}
}
public void doNotify() {
synchronized (lock) {
condition = true;
lock.notify();
System.out.println("Notified!");
}
}
public static void main(String[] args) {
WaitNotifyExample example = new WaitNotifyExample();
Thread waiter = new Thread(example::doWait);
Thread notifier = new Thread(example::doNotify);
waiter.start();
try {
Thread.sleep(1000); // Задержка для демонстрации ожидания
} catch (InterruptedException e) {
e.printStackTrace();
}
notifier.start();
}
}
#Java #Training #Multithreading #Medium
Что выведет код?
#Tasks
public class ArrayChallenge {
public static void main(String[] args) {
int[][] array = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int sum = 0;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
if (i == j || i + j == array.length - 1) {
sum += array[i][j];
}
}
}
System.out.println(sum);
}
}
#Tasks
This media is not supported in your browser
VIEW IN TELEGRAM
Напоминаю!🫡
Скорее всего, если магнитные бури не сотрут нас с лица земли, в воскресение (16:00 МСК) мы продолжим дописывать наше консольное TODO-приложение.
Приходите, будет интересно)😉
Можно будет и просто пообщаться) 🍻
Скорее всего, если магнитные бури не сотрут нас с лица земли, в воскресение (16:00 МСК) мы продолжим дописывать наше консольное TODO-приложение.
Приходите, будет интересно)😉
Продвинутые аспекты wait и notify
Метод notifyAll()
Метод notifyAll() пробуждает все потоки, ожидающие этого объекта. Это полезно в ситуациях, когда несколько потоков могут быть заинтересованы в событии.
Пример использования notifyAll():
Реальный пример: производитель-потребитель
Классическая задача, иллюстрирующая использование wait() и notify(), — это проблема "Производитель-потребитель". В этой задаче один или несколько производителей производят данные и добавляют их в общий буфер, а один или несколько потребителей извлекают данные из буфера.
Метод notifyAll()
Метод notifyAll() пробуждает все потоки, ожидающие этого объекта. Это полезно в ситуациях, когда несколько потоков могут быть заинтересованы в событии.
Пример использования notifyAll():
public class WaitNotifyExample {
private final Object lock = new Object();
private boolean condition = false;
public void doWait() {
synchronized (lock) {
while (!condition) {
try {
System.out.println(Thread.currentThread().getName() + " is waiting...");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " condition met!");
}
}
public void doNotifyAll() {
synchronized (lock) {
condition = true;
lock.notifyAll();
System.out.println("All notified!");
}
}
public static void main(String[] args) {
WaitNotifyExample example = new WaitNotifyExample();
Thread waiter1 = new Thread(example::doWait, "Waiter1");
Thread waiter2 = new Thread(example::doWait, "Waiter2");
Thread notifier = new Thread(example::doNotifyAll);
waiter1.start();
waiter2.start();
try {
Thread.sleep(1000); // Задержка для демонстрации ожидания
} catch (InterruptedException e) {
e.printStackTrace();
}
notifier.start();
}
}
Реальный пример: производитель-потребитель
Классическая задача, иллюстрирующая использование wait() и notify(), — это проблема "Производитель-потребитель". В этой задаче один или несколько производителей производят данные и добавляют их в общий буфер, а один или несколько потребителей извлекают данные из буфера.
import java.util.LinkedList;
import java.util.Queue;
class Buffer {
private final Queue<Integer> queue = new LinkedList<>();
private final int maxSize;
private final Object lock = new Object();
public Buffer(int maxSize) {
this.maxSize = maxSize;
}
public void produce(int value) throws InterruptedException {
synchronized (lock) {
while (queue.size() == maxSize) {
System.out.println("Buffer is full. Producer is waiting...");
lock.wait();
}
queue.add(value);
System.out.println("Produced: " + value);
lock.notifyAll();
}
}
public void consume() throws InterruptedException {
synchronized (lock) {
while (queue.isEmpty()) {
System.out.println("Buffer is empty. Consumer is waiting...");
lock.wait();
}
int value = queue.poll();
System.out.println("Consumed: " + value);
lock.notifyAll();
}
}
}
public class ProducerConsumerExample {
public static void main(String[] args) {
Buffer buffer = new Buffer(5);
Thread producer = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
buffer.produce(i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread consumer = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
buffer.consume();
Thread.sleep(150);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
producer.start();
consumer.start();
}
}
#Java #Training #Multithreading #Medium
Всем доброго солнечного утра!
Хотелось бы чтобы каждый подписчик ответил, что именно из контента ему больше нравится, а что не совсем)) Не стесняйтесь, сделаем канал лучше вместе! Итак что Вам нравится и чего надо побольше?
Хотелось бы чтобы каждый подписчик ответил, что именно из контента ему больше нравится, а что не совсем)) Не стесняйтесь, сделаем канал лучше вместе! Итак что Вам нравится и чего надо побольше?
Anonymous Poll
54%
Обучающих постов
0%
Мемов)))
38%
Задач
0%
Видео гайдов
0%
Онлайн встреч
0%
Всего более чем достаточно, можно и поменьше)))
8%
Я напишу свой вариант в комментариях!
This media is not supported in your browser
VIEW IN TELEGRAM
Запись нашей сегодняшней встречи -
https://www.youtube.com/watch?v=qNwDkOGJ96Q
Спасибо всем кто участвовал👍, продолжение на следующей неделе)))
https://www.youtube.com/watch?v=qNwDkOGJ96Q
Спасибо всем кто участвовал👍, продолжение на следующей неделе)))
Асинхронизм и Future в Java
Асинхронное программирование позволяет выполнять задачи в фоновом режиме, освобождая основной поток для выполнения других операций. Это особенно полезно для задач ввода-вывода, длительных вычислений и работы с внешними сервисами.
Асинхронное выполнение с использованием Future
Интерфейс Future из пакета java.util.concurrent представляет собой результат асинхронной операции. С помощью Future можно проверить, завершилась ли задача, дождаться ее завершения и получить результат.
Пример использования Future и ExecutorService:
Методы интерфейса Future
boolean cancel(boolean mayInterruptIfRunning): Пытается отменить выполнение задачи.
boolean isCancelled(): Возвращает true, если задача была отменена.
boolean isDone(): Возвращает true, если задача завершена.
V get(): Блокирует до завершения задачи и возвращает результат.
V get(long timeout, TimeUnit unit): Блокирует до завершения задачи или до истечения тайм-аута.
Пример использования методов Future:
#Java #Training #Multithreading #Medium
Асинхронное программирование позволяет выполнять задачи в фоновом режиме, освобождая основной поток для выполнения других операций. Это особенно полезно для задач ввода-вывода, длительных вычислений и работы с внешними сервисами.
Асинхронное выполнение с использованием Future
Интерфейс Future из пакета java.util.concurrent представляет собой результат асинхронной операции. С помощью Future можно проверить, завершилась ли задача, дождаться ее завершения и получить результат.
Пример использования Future и ExecutorService:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class FutureExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Callable<Integer> task = () -> {
Thread.sleep(2000);
return 42;
};
Future<Integer> future = executorService.submit(task);
// Выполняем другие задачи
System.out.println("Doing something else while the task is running...");
try {
// Блокируемся до завершения задачи и получаем результат
Integer result = future.get();
System.out.println("Task completed with result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
}
}
Методы интерфейса Future
boolean cancel(boolean mayInterruptIfRunning): Пытается отменить выполнение задачи.
boolean isCancelled(): Возвращает true, если задача была отменена.
boolean isDone(): Возвращает true, если задача завершена.
V get(): Блокирует до завершения задачи и возвращает результат.
V get(long timeout, TimeUnit unit): Блокирует до завершения задачи или до истечения тайм-аута.
Пример использования методов Future:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class FutureMethodsExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Callable<Integer> task = () -> {
Thread.sleep(3000);
return 42;
};
Future<Integer> future = executorService.submit(task);
try {
// Проверяем, завершена ли задача
if (!future.isDone()) {
System.out.println("Task is not completed yet...");
}
// Пытаемся получить результат с тайм-аутом
Integer result = future.get(2, TimeUnit.SECONDS);
System.out.println("Task completed with result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} catch (java.util.concurrent.TimeoutException e) {
System.out.println("Task timed out.");
} finally {
future.cancel(true); // Отменяем задачу, если она еще не завершена
executorService.shutdown();
}
}
}
#Java #Training #Multithreading #Medium
Что выведет код?
#Tasks
public class ArrayExample {
public static void main(String[] args) {
int[] array = new int[]{1, 2, 3, 4, 5};
int sum = 0;
for (int i = 0; i < array.length; i++) {
if (i % 2 == 0) {
sum += array[i];
} else {
sum -= array[i];
}
}
System.out.println(sum);
}
}
#Tasks