Jud*_*ing 0 java multithreading list spring-mvc
我正在使用SpringMVC,并且我有一个类AService作为缓冲区来存储列表String,在列表大小达到1000之后,将所有查询写入数据库.
@Service
class AService {
List<String> list;
public void addAndInsert(String query) {
list.add(query);
if(list.size() >= 1000) {
writeIntoDatabase(list);
list.clear();
}
}
}
Run Code Online (Sandbox Code Playgroud)
当只有一个线程时,这将正常工作.但是我们知道可以从不同的用户(当然是MultiThread)调用查询,所以我怎样才能保证这个工作正常:
当查询达到1000时,我想使用另一个线程来写入数据库,因为这个过程可能很长,我不希望用户等待那些与查询无关的东西.
查询不能丢失或重复.
谁能告诉我如何处理这种情况,List我应该使用哪种类的实现?谢谢!
我的回答分为两部分:
为了完整起见,我还要强调,如果您的JVM崩溃,您可以放弃查询.您声明查询不会丢失,但是在一分钟内所有内容都被保存在内存中.我认为你对此没问题.
同步添加到列表
虽然系统本身可以是多线程的,但Spring只会创建一个@Service类的单例,这意味着所有的Thread都访问同一个实例.因此,我们可以使用基本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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
此代码使用List实例的对象监视器来确保其上的所有操作都已同步.一个线程在列表上的操作必须在下一个之前完成.
调度将数据插入数据库
您已经说过要使用另一个Thread将数据插入数据库.我建议你熟悉包中的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.
}
}
Run Code Online (Sandbox Code Playgroud)