Java使用多线程持久化列表

时间:2019-02-08 17:22:11

标签: java database multithreading collections persist

我需要创建一个列表以执行以下操作:

  1. 我每微秒从外部队列/主题接收一个对象。
  2. 对对象执行一些操作后,我需要将这些对象持久保存到数据库中。
  3. 我正在以100或1000的批次进行持久化。唯一的问题是,持久化速率低于传入的消息速率。现在,我不想将其保留在单个线程中,因为持久将降低消息的消耗。
  4. 我的想法是继续接受消息对象并将其添加到集合(如链接列表)
  5. 并继续以100或1000的批次从集合的另一端删除并保存到数据库中。
  6. 最适合使用什么收藏?如何同步它并避免并发修改异常?

下面是我要使用ArrayList实施的代码,该代码每秒钟保持一次就清除列表。

class myclass{
List persistList;
ScheduledExecutorService persistExecutor;
ScheduledFuture scheduledFuture;
PersistOperation persistOperation;
//Initialize delay, interval
void init(){
scheduledFuture=persistExecutor.scheduleAtFixedRate(new persistOperation(persistList), delay, interval, TimeUnit.SECONDS);
}
void execute(msg){
//process the message and add to the persist list
}
class PersistOperation implements Runnable{
List persistList
PersistOperation(List persistList){
//Parameterized constructor
}
run(){
//Copy persistList to new ArrayList and clear persistList
//entity manager persist/update/merge
}
}
}

3 个答案:

答案 0 :(得分:1)

  

并继续以100或1000的批次从集合的另一端删除并保存到数据库中。

这是合理的,只要从集合中轮询多个线程即可。

  

下面是我要使用ArrayList实现的代码

在这里ArrayList是一个不好的选择,因为它不是线程安全的,并且在删除索引0上的元素时,必须移至其右边的每个元素({ {1}}操作。

您要查找的集合称为O(n),也称为双端队列。但是,由于您需要集合具有线程安全性,因此我建议使用Deque

答案 1 :(得分:0)

我认为您将在这里使用LMAX Disruptor framework。我设想了两个RingBuffer。您将使用第一个接受传入的消息。您的工作人员将从RingBuffer中读取。您可以将RingBuffer的大小设置为等于您的持久块大小(例如100或1000)。工作者从RingBuffer接收事件并对其进行处理后,会将对持久对象的引用放置到Queue Collection中。每次第一个RingBuffer圈了一次,您就分配一个新的Queue,并将旧的Queue放入第二个RingBuffer。第二个RingBuffer的工作程序从RingBuffer中获取一个Queue对象,将所有对象保留在Queue中,然后移至下一个队列。您可以调整第二个RingBuffer和工作线程的大小,以适应数据库可以持久存储块的速度。

答案 2 :(得分:0)

使用这种方法可能会丢失消息,如果您收到100条消息但未保存,并且应用程序死了,您是否有能力丢失这些消息? 主题/队列的类型在这里很重要,主题具有管理此反压控制的优势,由于需要顺序处理,因此通常存在队列。 如果您排队/主题是kafka,并且您提取消息,kafka可以提取批次,并且您也可以将批次保存到数据库中,仅在保存消息后才将消息确认到kafka。 如果需要订购处理程序,则可以处理一些被动方法并调整数据库。通常,队列系统可以控制流量。