Урок 25: Синхронизация потоков
Синхронизация потоков в Java необходима для обеспечения корректного доступа к общим ресурсам в многопоточной среде. Синхронизация позволяет избежать состояния гонки, когда несколько потоков одновременно изменяют общий ресурс. В Java для синхронизации используется ключевое слово synchronized
, которое можно применять к методам и блокам кода.
Синхронизированные методы
Методы могут быть объявлены как synchronized
, что гарантирует, что только один поток может выполнять этот метод в определенный момент времени:
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class SynchronizedMethodExample {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Count: " + counter.getCount());
}
}
Результат выполнения
Синхронизированные блоки
Синхронизированные блоки позволяют ограничить область синхронизации, что может повысить производительность:
class Counter {
private int count = 0;
public void increment() {
synchronized (this) {
count++;
}
}
public int getCount() {
return count;
}
}
public class SynchronizedBlockExample {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Count: " + counter.getCount());
}
}
Результат выполнения
Упражнения
Упражнение 1: Синхронизация метода
Напишите программу, которая создает банк, в котором два потока одновременно вносят и снимают деньги с общего счета. Обеспечьте синхронизацию методов для внесения и снятия денег.
Решение:
class BankAccount {
private int balance = 1000;
public synchronized void deposit(int amount) {
balance += amount;
}
public synchronized void withdraw(int amount) {
balance -= amount;
}
public int getBalance() {
return balance;
}
}
public class BankExample {
public static void main(String[] args) {
BankAccount account = new BankAccount();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
account.deposit(100);
System.out.println("Deposited 100, balance: " + account.getBalance());
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
account.withdraw(100);
System.out.println("Withdrew 100, balance: " + account.getBalance());
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final balance: " + account.getBalance());
}
}
Объяснение: Программа создает объект BankAccount
и два потока, которые одновременно вносят и снимают деньги с счета. Методы deposit
и withdraw
синхронизированы, что предотвращает одновременное изменение баланса счета несколькими потоками.
Упражнение 2: Синхронизация блока
Напишите программу, которая создает общий счетчик и два потока, которые увеличивают счетчик. Используйте синхронизированный блок для увеличения значения счетчика.
Решение:
class SharedCounter {
private int count = 0;
public void increment() {
synchronized (this) {
count++;
}
}
public int getCount() {
return count;
}
}
public class SynchronizedBlockExample {
public static void main(String[] args) {
SharedCounter counter = new SharedCounter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final count: " + counter.getCount());
}
}
Объяснение: Программа создает объект SharedCounter
и два потока, которые одновременно увеличивают значение счетчика. Для синхронизации используется блок synchronized
внутри метода increment
.