Как сделаешь synchronized блок в статическом методе
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Синхронизация в статических методах Java
Синхронизация в статических методах требует особого внимания, потому что статические члены класса являются общими для всех экземпляров и даже доступны без создания объектов. Есть несколько способов реализации.
Способ 1: Synchronized modifier на методе
Это самый простой и понятный подход — синхронизация происходит на уровне всего метода:
public class Counter {
private static int count = 0;
// Синхронизируется на объекте Class
public synchronized static void increment() {
count++;
}
public synchronized static int getCount() {
return count;
}
}
В этом случае блокировка происходит на объекте Class (Counter.class), и только один поток может находиться в этом методе одновременно.
Способ 2: Synchronized блок с ClassName.class
Этот подход даёт больше гибкости — можно синхронизировать только критическую секцию:
public class BankAccount {
private static int balance = 1000;
public static void transfer(int amount) {
System.out.println("Начало операции трансфера");
// Только эта часть потокобезопасна
synchronized (BankAccount.class) {
if (balance >= amount) {
balance -= amount;
System.out.println("Переведено: " + amount);
} else {
System.out.println("Недостаточно средств");
}
}
System.out.println("Конец операции трансфера");
}
public static int getBalance() {
synchronized (BankAccount.class) {
return balance;
}
}
}
Способ 3: Synchronized с помощью отдельного статического объекта
Иногда нужна более тонкая синхронизация между несколькими методами:
public class SharedResource {
private static final Object LOCK = new Object();
private static List<String> items = new ArrayList<>();
public static void addItem(String item) {
synchronized (LOCK) {
items.add(item);
System.out.println("Добавлен: " + item);
}
}
public static void removeItem(String item) {
synchronized (LOCK) {
items.remove(item);
System.out.println("Удален: " + item);
}
}
}
Это полезно, когда нужно синхронизировать несколько методов без глобальной блокировки класса.
Способ 4: ReentrantLock (современный подход)
Для более сложных сценариев используй ReentrantLock:
public class AdvancedCounter {
private static final ReentrantLock lock = new ReentrantLock();
private static int count = 0;
public static void increment() {
lock.lock();
try {
count++;
System.out.println("Счетчик: " + count);
} finally {
lock.unlock();
}
}
public static int getCountWithTimeout() {
try {
if (lock.tryLock(5, TimeUnit.SECONDS)) {
try {
return count;
} finally {
lock.unlock();
}
} else {
System.out.println("Не удалось получить блокировку");
return -1;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return -1;
}
}
}
Практический пример с потокобезопасностью
public class DatabaseConnection {
private static Connection connection;
private static final Object connectionLock = new Object();
public static Connection getConnection(String url) {
synchronized (connectionLock) {
if (connection == null) {
try {
connection = DriverManager.getConnection(url);
} catch (SQLException e) {
e.printStackTrace();
}
}
return connection;
}
}
}
Важные моменты
- synchronized методе: блокировка на Class объекте (ClassName.class)
- synchronized блоке: блокировка на указанном объекте (обычно Class или создать отдельный Object)
- ReentrantLock: больше контроля, позволяет попытаться получить блокировку с timeout
- Производительность: synchronized блоки быстрее, чем синхронизация всего метода
Выбор способа зависит от требований: для простых случаев достаточно synchronized блока, для сложных — используй ReentrantLock с условиями (Condition).