Jeśli mam klasę util ze statycznymi metodami, które będą wywoływać funkcje Hibernate w celu uzyskania podstawowego dostępu do danych. Zastanawiam się, czy wykonanie tej metody synchronized
jest właściwym podejściem do zapewnienia bezpieczeństwa nici.
Chcę, aby to uniemożliwiło dostęp do informacji do tej samej instancji bazy danych. Jednak jestem teraz pewien, czy poniższy kod uniemożliwia getObjectById
wywołanie wszystkich klas, gdy jest wywoływany przez określoną klasę.
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
}
For a class (static) method, the monitor associated with the Class object for the method's class is used. For an instance method, the monitor associated with this (the object for which the method was invoked) is used.
Tak więc, jeśli jeden wątek przechodzi do metody statycznej, ten sam obiekt zwracany przez Object # getClass jest blokowany. Inne wątki nadal mogą uzyskiwać dostęp do metod instancji.Class
obiekt, którego instancja jest tworzona przez jeden z programów ładujących klasy maszyn wirtualnych. Podobnie jak wszystkie obiekty, ten obiekt również maMonitor
z nim skojarzony. A ten monitor jest tym, co jest blokowane.Aby odpowiedzieć na pytanie bardziej ogólnie ...
Pamiętaj, że używanie zsynchronizowanych metod jest naprawdę skrótowe (zakładając, że klasa to SomeClass):
jest taki sam jak
i
jest taki sam jak
Możesz użyć dowolnego przedmiotu jako zamka. Jeśli chcesz zablokować podzbiory metod statycznych, możesz to zrobić
(w przypadku metod niestatycznych chciałbyś, aby blokady były polami niestatycznymi)
źródło
Metody statyczne używają klasy jako obiektu do blokowania, którym na przykład jest Utils.class. Więc tak, jest OK.
źródło
static synchronized
oznacza utrzymywanie blokady na obiekcie klasy,Class
gdzie jakosynchronized
oznacza utrzymywanie blokady na samym obiekcie tej klasy. Oznacza to, że jeśli uzyskujesz dostęp do niestatycznej metody synchronizowanej w wątku (wykonywania), nadal możesz uzyskać dostęp do statycznej metody synchronizowanej przy użyciu innego wątku.Zatem dostęp do dwóch metod tego samego rodzaju (albo dwóch statycznych albo dwóch niestatycznych) w dowolnym momencie przez więcej niż jeden wątek nie jest możliwy.
źródło
Dlaczego chcesz wymusić, że tylko jeden wątek może uzyskać dostęp do bazy danych w dowolnym momencie?
Zadaniem sterownika bazy danych jest zaimplementowanie wszelkich niezbędnych blokad, zakładając, że
Connection
w danym momencie a jest używany tylko przez jeden wątek!Najprawdopodobniej Twoja baza danych doskonale radzi sobie z wielokrotnym dostępem równoległym
źródło
Jeśli ma to coś wspólnego z danymi w Twojej bazie danych, dlaczego nie wykorzystać do tego blokowania izolacji bazy danych?
źródło
Odpowiadając na twoje pytanie, tak: twoja
synchronized
metoda nie może być wykonywana jednocześnie przez więcej niż jeden wątek.źródło
Jak
synchronized
działa słowo kluczowe JavaPo dodaniu
synchronized
słowa kluczowego do metody statycznej metoda może być wywoływana jednocześnie tylko przez jeden wątek.W twoim przypadku każde wywołanie metody:
SessionFactory
Session
Jednak takie były Twoje wymagania:
getObjectById
wywoływaniu wszystkich klas, gdy jest wywoływane przez określoną klasęTak więc, nawet jeśli
getObjectById
metoda jest bezpieczna dla wątków, implementacja jest nieprawidłowa.SessionFactory
najlepsze praktykiSessionFactory
Jest thread-safe, i jest to bardzo kosztowny obiekt do tworzenia, ile potrzebuje do analizowania klas encji i budować wewnętrzną reprezentację podmiotu metamodel.Dlatego nie powinieneś tworzyć wywołania metody
SessionFactory
przy każdymgetObjectById
wywołaniu.Zamiast tego należy utworzyć dla niego pojedynczą instancję.
Session
Powinny być zawsze zamknięteNie zamknąłeś bloku
Session
wfinally
bloku, co może spowodować wyciek zasobów bazy danych, jeśli podczas ładowania jednostki zostanie zgłoszony wyjątek.Zgodnie z
Session.load
metodą JavaDoc możeHibernateException
zgłosić, jeśli jednostka nie może zostać znaleziona w bazie danych.Dlatego musisz użyć
finally
bloku, aby zamknąćSession
, w ten sposób:Zapobieganie dostępowi do wielu wątków
W twoim przypadku chciałeś mieć pewność, że tylko jeden wątek uzyska dostęp do tej konkretnej jednostki.
Ale
synchronized
słowo kluczowe zapobiega tylkogetObjectById
równoczesnemu wywoływaniu dwóch wątków . Jeśli dwa wątki wywołują tę metodę jeden po drugim, nadal będziesz mieć dwa wątki korzystające z tej jednostki.Tak więc, jeśli chcesz zablokować dany obiekt bazy danych, aby żaden inny wątek nie mógł go zmodyfikować, musisz użyć blokad bazy danych.
Słowo
synchronized
kluczowe działa tylko w pojedynczej maszynie JVM. Jeśli masz wiele węzłów WWW, nie zapobiegnie to wielowątkowemu dostępowi do wielu maszyn JVM.To, co musisz zrobić, to użyć
LockModeType.PESSIMISTIC_READ
lubLockModeType.PESSIMISTIC_WRITE
podczas stosowania zmian w bazie danych, na przykład:Tak więc zrobiłem:
EntityTransaction
i rozpocząłem nową transakcję w bazie danychPost
jednostkę, trzymając blokadę skojarzonego rekordu bazy danychPost
podmiot i dokonałem transakcjiException
wyrzucenia wycofałem transakcjęźródło