我的回答分为两部分:
- 将查询项添加到列表的同步
- 安排将查询数据插入数据库
为了完整起见,我还将强调,如果您的 JVM 崩溃,您可能会丢失查询。您声明查询不会丢失,但此刻所有内容都保存在内存中。我假设你对此没有意见。
同步添加到列表
虽然系统本质上可以是多线程的,但 Spring 只会创建@Service
类的单例,这意味着所有线程都访问同一个实例。因此,我们可以使用基本的 Java 功能很容易地同步对该实例的成员变量的访问。
JDK 确实提供了一些开箱即用的基本同步 List 实现。例如,看一下Collections.synchronizedList()或CopyOnWriteArrayList。
这些实现通常为列表上的单个操作提供同步,例如 add() 或 get()。它们不提供跨多个方法调用的同步。然而,基本的 Java 同步可以让我们实现这一点:
public void addAndInsert(String query)
{
synchronized(list)
{
list.add(query);
if(list.size() >= 1000)
{
writeIntoDatabase(list);
list.clear();
}
}
}
此代码使用 List 实例的对象监视器来确保对其进行的所有操作都是同步的。一个线程对列表的操作必须在下一个线程之前完成。
计划将数据插入数据库
您说过您想使用另一个线程将数据插入数据库。我建议你熟悉一下包中的ExecutorService接口java.util.concurrent
。这提供了出色的实现,提供托管的线程池来执行任务。根据您所说,我建议ThreadPoolExecutor非常适合您的需求。您还必须记住将列表中的数据副本传递给另一个线程,以便您的List.clear()
操作不会干扰插入到数据库中。
所以这会给我们留下类似于以下内容的最终代码:
@Service
public class AService
{
private List<String> list;
private ExecutorService executorService;
public void addAndInsert(String query)
{
synchronized(list)
{
list.add(query);
if(list.size() >= 1000)
{
executorService.execute(writeIntoDataBase(new LinkedList<String>(list)));
list.clear();
}
}
}
private Runnable writeIntoDataBase(List<String> list)
{
//TODO - Create your Runnable to write data to the db.
}
}