gpt4 book ai didi

java - 为什么这种锁变化对 JDBC 性能的影响如此之大?

转载 作者:行者123 更新时间:2023-11-29 09:16:29 25 4
gpt4 key购买 nike

我正在编写一个用于大型多线程应用程序的数据库连接池,编写目标为 jdk4 标准,使用以下代码我可以使用我的测试用例在 0.4 秒内通过 LAN 查询 mysql 数据库 1000 次。

synchronized(lockA) {
if(free.size() > 0) {
c = (Connection) free.removeFirst();
}

if(c == null) {
c = DriverManager.getConnection(query, name, passw);
}
}

这里lockA保护的是空闲链表(LinkedList),它用在链表被修改和访问的地方。将 getConnection 从这个锁中移出并移到它自己的 protected block 中是有意义的。 getConnection 需要用锁保护,因为它在某处不是线程安全的。

因此,如果我更改它,DriverManager 和列表将受到单独的锁的保护,就像这样。

synchronized(lockA) {
if(free.size() > 0) {
c = (Connection) free.removeFirst();
}
}

if(c == null) {
synchronized(lockB) {
c = DriverManager.getConnection(query, name, passw);
}
}

我得到连续的缓存未命中(C 为空),因此性能降低,以至于执行相同的查询需要 4 秒,而原来需要 0.4 秒。

为什么会这样?

编辑:

我已经解决了这个问题,问题出在创建过多连接时函数阻塞的方式。

这就是函数开始时发生的事情。

synchronized(waitLocK) {
try {
while(count >= limit) {
waitLock.wait();
}
} catch (InterruptedException e) {
}
}

waitLock 在释放连接时被释放。但这里发生的是,在创建连接的代码块之后,计数变量(volatile)递增。

这具有打开大门的效果,因为当 1000 个线程试图通过等待测试时,它们都通过了,因为计数仍然为 0,然后重载了 getConnection()。

将 count++ 移到 try 之后解决了这个问题。

最佳答案

第二种形式的代码允许无限数量的线程同时请求连接到数据库,而第一种形式一次只允许一个线程请求新连接。

在用 Java 编写并发代码时,我有一个简单的规则要遵循:

如果您的代码中包含 synchronized 关键字,则它可能是错误的,并且会以微妙且不可预测的方式失败。

开个玩笑,您需要长期认真地思考为什么您无法使用标准并发类实现您想要的并发结果。

skaffman 的评论是正确的——您真的不想实现连接池。选择任何一个可用的实现。

不过,假设这不是一个连接池。为什么使用同步+LinkedList,而不是ConcurrentLinkedQueue?您的逻辑试图从列表中获取连接;如果没有可用连接,它会创建一个新连接(据推测,调用者会在完成连接后释放回列表)。

Java Concurrency In Practice是一本很棒的书,如果你还没有读过的话。

关于java - 为什么这种锁变化对 JDBC 性能的影响如此之大?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9093884/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com