Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 数据库的多线程问题_Java_Multithreading_Hibernate_Concurrency - Fatal编程技术网

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来回转换(意味着:如果需要从数据库中选择输出以丰富数据集,则在遍历文件时预先读取它,而不是不停地读取)
更新----

根据我的评论,在解析文件时,可能需要从数据库中获取数据。好吧,如果你必须这么做,你必须这么做。但是:尽量不要这样做

首先:可以看到读取特定数据是否缓存。狭义地说,缓存只是通过任何启发式方法将磁盘数据移动到内存中(不知道发生了什么)。我个人尽量避免这种情况,因为启发法可能会对你不利。在更广泛的理解中,缓存是我前面描述的,并将数据从磁盘放到内存中,您可以精确定位(例如,通过ID或任何筛选条件)。因此,我仍然不喜欢这种狭隘的理解,而是喜欢预先选择定义良好的数据的行为

第二:我的个人经历是这样的:如果你正在处理一个完全规范化的数据模型数据库,那么在文件parsings中的读取操作通常会简化为“给我一个主键”,即我之前转储到数据库中的内容。当您同时写入多行时,这似乎变得很棘手。然而,特别是在MySQL中,您可以肯定地依赖“每个insert语句(甚至多行insert)都是原子的”,您可以从上一个\u insert\u ID()获得ID,因此您可以跟踪到以前编写的所有记录。我很确定其他数据库系统也有类似的“故障”


第三:解析大文件是我会尝试的工作,只有一个技术用户触发,以确保不超过1个进程并行运行。否则,您需要解决所有类型的问题,从文件锁定到会话权限读/写管理。因此,将此作为作业进行分类(至少在我的个人策略中)以分配大量RAM—这取决于成本和速度的重要性。这意味着我甚至不必预先将100K行关键字加载到id表的内存中。

我不明白为什么在removeClientResolutionActive中删除CountDownLatch,即使它不是零!?我也不明白你为什么不为第一次通话创建一个下行锁存器。这就像你试图将它设置为“null”,就像你想保留一些内存一样。在删除之后,我调用
倒计时
方法。我有一些线程,但这并不意味着所有线程都需要相同的客户端。如果有第二个线程,你就知道有两个线程。但是第二个或第一个(或第三个)线程将删除倒计时。所以它是无用的。下一个线程将找不到它。(我谈论的是在同一个客户机上工作的线程),其想法是只有一个线程可以创建客户机并移除闩锁。因此,在
锁之后有一个
get
。wait
。那么最后一点是从数据库创建缓存?解析文件时存储在数据库中的对象如何?谢谢。:)我注意到我应该用书面语而不是储存在句子中。数据库在分析文件时正在增长。@CSchulz:不确定,你是什么意思?从属对象?问题是什么?混合对数据库的读取和写入不是b
insert into urtable 
values
('val1','val2'),
('val1','val2');