如果我有一个util类,它的静态方法将调用Hibernate函数来完成基本的数据访问,我想知道创建方法synchronized
是否是确保线程安全的正确方法。
我希望这样可以防止信息被访问到相同的DB示例。但是,我现在可以确定下面的代码是否可以防止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
}
8条答案
按热度按时间x33g5p2x1#
为了更全面地回答这个问题...
请记住,在方法上使用synchronized实际上只是一种简化(假设class是
SomeClass
):等于
以及
等于
可以使用任何对象作为锁。如果要锁定静态方法的子集,可以
(for非静态方法,您可能希望将锁设置为非静态字段)
up9lanfz2#
通过在静态方法锁上使用synchronized,您将同步类方法和属性(与示例方法和属性相对)
所以你的假设是正确的。
不完全是。你应该让你的关系数据库管理系统来做那项工作。他们很擅长这类事情。
同步数据库访问的唯一好处是会让应用程序变得非常慢。此外,在你发布的代码中,你每次都在构建一个会话工厂,这样,你的应用程序访问数据库的时间会比执行实际任务的时间多。
想象一下下面的场景:
客户机A和B试图向表T的记录X插入不同的信息。
使用你的方法,你得到的唯一的东西是确保一个在另一个之后被调用,当这种情况无论如何都会在DB中发生时,因为RDBMS将阻止他们同时插入来自A的一半信息和来自B的一半信息,结果将是相同的,但只是慢了5倍(或更多)。
也许看一下Hibernate文档中的"Transactions and Concurrency"章节会更好,大多数时候你试图解决的问题已经解决了,而且是一个更好的方法。
vxf3dgd43#
静态方法使用类作为锁的对象,在你的例子中是Utils.class,所以是的,这是可以的。
s8vozzvw4#
static synchronized
意味着在类的Class
对象上持有锁,而synchronized
意味着在类的示例上持有锁。这意味着,如果你在一个线程(执行)中访问一个非静态同步方法,你仍然可以使用另一个线程访问一个静态同步方法。因此,在任何时间点由多个线程访问两个相同类型的方法(两个静态或两个非静态方法)是不可能的。
9lowa7mx5#
为什么要强制在任何时候只有一个线程可以访问DB?
Connection
一次仅由一个线程使用!最有可能的是,您的数据库完全能够处理多个并行访问
pkln4tw66#
如果是与数据库中的数据有关的东西,为什么不利用数据库隔离锁来实现呢?
flmtquvp7#
回答你的问题,是的:你的
synchronized
方法不能被一个以上的线程同时执行.omjgkv6w8#
synchronized
Java关键字的工作原理向静态方法添加
synchronized
关键字时,该方法一次只能由一个线程调用。在您的情况下,每个方法调用都将:
SessionFactory
Session
但是,这些是你的要求:
getObjectById
在被特定类调用时被所有类调用因此,即使
getObjectById
方法是线程安全的,实现也是错误的。SessionFactory
最佳实践SessionFactory
是线程安全的,创建它是一个开销非常大的对象,因为它需要解析实体类并构建内部实体元模型表示。因此,您不应该在每次
getObjectById
方法调用时创建SessionFactory
。相反,您应该为它创建一个单例示例。
Session
应始终处于关闭状态您没有关闭
finally
块中的Session
,如果在加载实体时引发异常,这可能会泄漏数据库资源。根据
Session.load
方法,如果在数据库中找不到实体,JavaDoc可能会抛出HibernateException
。不应使用此方法来确定示例是否存在(请改用
get()
)。仅在检索假定存在的示例时才使用此方法,否则将导致实际错误。这就是为什么需要使用
finally
块来关闭Session
,如下所示:防止多线程访问
在您的示例中,您希望确保只有一个线程可以访问该特定实体。
但是
synchronized
关键字只是防止两个线程同时调用getObjectById
,如果两个线程相继调用这个方法,你仍然会有两个线程使用这个实体。因此,如果您希望锁定给定的数据库对象,使其他线程无法修改它,那么您需要使用数据库锁。
关键字
synchronized
只在单个JVM中有效,如果您有多个Web节点,这将不会阻止跨多个JVM的多线程访问。您需要做的是在将更改应用到DB时使用
LockModeType.PESSIMISTIC_READ
orLockModeType.PESSIMISTIC_WRITE
,如下所示:这就是我所做的
EntityTransaction
并启动了一个新的数据库事务Post
实体,同时锁定了关联的数据库记录Post
实体并提交了事务Exception
的情况下,我回滚了事务