Как синхронизированные статические методы работают в Java? - PullRequest
170 голосов
/ 23 февраля 2009

Если у меня есть класс util со статическими методами, которые будут вызывать функции Hibernate для выполнения базового доступа к данным. Мне интересно, если метод synchronized является правильным подходом для обеспечения безопасности потока.

Я хочу, чтобы это предотвратило доступ информации к тому же экземпляру БД. Однако теперь я уверен, что следующий код запрещает вызов getObjectById для всех классов, когда он вызывается определенным классом.

public class Utils {
     public static synchronized Object getObjectById (Class objclass, Long id) {
           // call hibernate class
         Session session = new Configuration().configure().buildSessionFactory().openSession();
         Object obj = session.load(objclass, id);
         session.close();
         return obj;
     }

     // other static methods
}

Ответы [ 7 ]

221 голосов
/ 24 февраля 2009

Для более общего решения вопроса ...

Имейте в виду, что использование синхронизированных методов на самом деле является просто сокращением (предположим, класс это SomeClass):

synchronized static void foo() {
    ...
}

совпадает с

static void foo() {
    synchronized(SomeClass.class) {
        ...
    }
}

и

synchronized void foo() {
    ...
}

совпадает с

void foo() {
    synchronized(this) {
        ...
    }
}

Вы можете использовать любой объект в качестве замка. Если вы хотите заблокировать подмножества статических методов, вы можете

class SomeClass {
    private static final Object LOCK_1 = new Object() {};
    private static final Object LOCK_2 = new Object() {};
    static void foo() {
        synchronized(LOCK_1) {...}
    }
    static void fee() {
        synchronized(LOCK_1) {...}
    }
    static void fie() {
        synchronized(LOCK_2) {...}
    }
    static void fo() {
        synchronized(LOCK_2) {...}
    }
}

(для нестатических методов вы бы хотели, чтобы блокировки были нестатическими полями)

134 голосов
/ 23 февраля 2009

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

Итак, ваше предположение верно.

Мне интересно, является ли синхронизация метода правильным подходом для обеспечения безопасности потоков.

Не совсем. Вы должны позволить этой работе делать ваши RDBMS вместо этого. Они хороши в таких вещах.

Единственное, что вы получите, синхронизировав доступ к базе данных, это сделайте ваше приложение ужасно медленным. Более того, в коде, который вы разместили, вы каждый раз создаете фабрику сессий, таким образом, ваше приложение будет тратить больше времени на доступ к БД, чем на выполнение реальной работы.

Представьте себе следующий сценарий:

Клиенты A и B пытаются вставить различную информацию в запись X таблицы T.

При вашем подходе единственное, что вы получаете, - это убедиться, что один вызывается после другого, когда это все равно произойдет в БД, потому что СУБД не позволит им вставлять половину информации из A и половину из B в в то же время. Результат будет таким же, но только в 5 (или более) раз медленнее.

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

17 голосов
/ 23 февраля 2009

Статические методы используют класс в качестве объекта для блокировки, который для вашего примера является Utils.class. Так что да, все в порядке.

14 голосов
/ 19 апреля 2011

static synchronized означает удержание блокировки на объекте Class класса в то время как synchronized означает блокировку самого объекта этого класса. Это означает, что если вы обращаетесь к нестатическому синхронизированному методу в потоке (выполнения), вы все равно можете получить доступ к статическому синхронизированному методу, используя другой поток.

Таким образом, доступ к двум методам одного типа (двум статическим или двум нестатическим методам) в любой момент времени более чем одним потоком невозможен.

9 голосов
/ 23 февраля 2009

Почему вы хотите обеспечить, чтобы только один поток мог одновременно обращаться к БД?

Задача драйвера базы данных - реализовать любую необходимую блокировку, предполагая, что Connection используется только одним потоком за раз!

Скорее всего, ваша база данных вполне способна обрабатывать множественный параллельный доступ

2 голосов
/ 23 февраля 2009

Чтобы ответить на ваш вопрос, да, это так: ваш метод synchronized не может быть выполнен более чем одним потоком одновременно.

2 голосов
/ 23 февраля 2009

Если это связано с данными в вашей базе данных, почему бы не использовать для этого изоляцию базы данных?

...