Java 数据库的多线程问题
我想解析一个文件并将内容传输到数据库中。要加速所有操作,应并行解析文件。Java 数据库的多线程问题,java,multithreading,hibernate,concurrency,Java,Multithreading,Hibernate,Concurrency,我想解析一个文件并将内容传输到数据库中。要加速所有操作,应并行解析文件。 我有一个主线程,它正在逐行读取文件并创建Runnable,这是给ThreadPoolExecutor的。每个Runnable都有自己的会话 每一行都包含一个客户端的唯一标识符,因此可以重复。系统尝试通过标识符在数据库中查找客户端。 如果找不到需要相同客户端的线程之一,则需要创建客户端。这里有一个“连接”点,其他线程必须等待允许创建客户机的线程 c = (Client) s.get("Client", identfier);
我有一个主线程,它正在逐行读取文件并创建Runnable,这是给ThreadPoolExecutor的。每个Runnable都有自己的会话 每一行都包含一个客户端的唯一标识符,因此可以重复。系统尝试通过标识符在数据库中查找客户端。
如果找不到需要相同客户端的线程之一,则需要创建客户端。这里有一个“连接”点,其他线程必须等待允许创建客户机的线程
c = (Client) s.get("Client", identfier);
if (c == null) {
CountDownLatch lock = isClientResolutionActive(identfier);
if (lock != null) {
lock.await();
LOGGER.info("Lock was released ... " + identfier);
c = (Client) s.get("Client", identfier);
}
}
if (c == null) {
c = createClient(...);
s.save(c);
s.flush();
removeClientResolutionActive(identfier);
}
为了同步它们,我在caller类中创建了两个方法,一个方法用于检查是否已经有人在创建客户端并返回共享对象,另一个方法从列表中删除条目并通知所有等待的线程
我在互联网上搜索了很多,试图找到我的问题或类似问题,但没有成功。此外,我不确定应该使用哪个并发对象。经过研究,我决定倒计时。它是用1初始化的。应该只有一个线程创建它。(也许使用倒计时锁以外的其他工具会更好,但我不知道是什么) 上述方法在映射上包含一个synchronized块,该块保存客户机的标识符和CountDownLatch实例 一般来说,它工作正常,但有时我会遇到问题,当闩锁被释放(并被删除)并且access synchronized变量队列包含另一个线程来搜索已删除的条目(以检查是否有线程正在执行此操作)时,它会尝试再次创建新的客户端
18:02:55,611 [pool-1-thread-2] INFO LogImporter Unlock b42fcae346fbb2b1e3c544fb816de2c5
18:02:55,611 [pool-1-thread-3] INFO LogImporter Locked b42fcae346fbb2b1e3c544fb816de2c5
18:02:55,611 [pool-1-thread-4] INFO LogImporter Lock was released ... b42fcae346fbb2b1e3c544fb816de2c5
我认为我必须改进同步,但我不知道如何改进
一种方法是将客户端搜索移动到synchronized块中,或者在再次锁定数据库之前进行检查。也许可以创建一个缓存或映射,用于保存数据库中所有已知的客户端。
或者在应用程序的整个生命周期中只使用一个会话
提前感谢您的建议和提示。在并行线程中解析同一文件不会提高速度,但只会增加额外资源 问题更少、效率更高的text2db优化包括:
- 大容量读取文件(而不是一次逐行读取1MB,处理它,读取下一个MB)
- 批量插入数据库-mysql,如下所示:
insert into urtable values ('val1','val2'), ('val1','val2');
- 尝试防止sql来回转换(意味着:如果需要从数据库中选择输出以丰富数据集,则在遍历文件时预先读取它,而不是不停地读取)
第三:解析大文件是我会尝试的工作,只有一个技术用户触发,以确保不超过1个进程并行运行。否则,您需要解决所有类型的问题,从文件锁定到会话权限读/写管理。因此,将此作为作业进行分类(至少在我的个人策略中)以分配大量RAM—这取决于成本和速度的重要性。这意味着我甚至不必预先将100K行关键字加载到id表的内存中。我不明白为什么在removeClientResolutionActive中删除CountDownLatch,即使它不是零!?我也不明白你为什么不为第一次通话创建一个下行锁存器。这就像你试图将它设置为“null”,就像你想保留一些内存一样。在删除之后,我调用
倒计时
方法。我有一些线程,但这并不意味着所有线程都需要相同的客户端。如果有第二个线程,你就知道有两个线程。但是第二个或第一个(或第三个)线程将删除倒计时。所以它是无用的。下一个线程将找不到它。(我谈论的是在同一个客户机上工作的线程),其想法是只有一个线程可以创建客户机并移除闩锁。因此,在锁之后有一个get
。wait
。那么最后一点是从数据库创建缓存?解析文件时存储在数据库中的对象如何?谢谢。:)我注意到我应该用书面语而不是储存在句子中。数据库在分析文件时正在增长。@CSchulz:不确定,你是什么意思?从属对象?问题是什么?混合对数据库的读取和写入不是b
insert into urtable
values
('val1','val2'),
('val1','val2');