如何在Java中使用List Class当需要多线程时?

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)调用查询,所以我怎样才能保证这个工作正常:

  1. 当查询达到1000时,我想使用另一个线程来写入数据库,因为这个过程可能很长,我不希望用户等待那些与查询无关的东西.

  2. 查询不能丢失或重复.

谁能告诉我如何处理这种情况,List我应该使用哪种类的实现?谢谢!

Rob*_*ake 5

我的回答分为两部分:

  • 将查询项添加到列表的同步
  • 将查询数据的插入计划到数据库中

为了完整起见,我还要强调,如果您的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)