我有多个线程在lucene索引中执行搜索。在每次搜索之前,检查内容是否已经编入索引,如果没有,则将其添加到索引中。如果对未编入索引的内容进行两次并行搜索同时发生,则会有重复的文档并猜测搜索结果将被搞砸。
我找到了以下方法:IndexWriter.updateDocument
但我认为这并不能解决我所面临的多线程问题。
如何解决此问题的任何建议都表示赞赏。
答案 0 :(得分:1)
首先确保一次只有一个方法(IndexWriter#updateDocument()
)调用,你可以使用属于你的线程的共享对象实现它,就像这样
class Search implements Runnable{
private Object lock=new Object();
private volatile boolean found=false;
public void run(){
//business
if(<<found something!>> && !found){
synchronized(lock){/*call the related-method*/found=true;}
}
//business
}
}
其次,您需要跟踪搜索过程中找到的每个键,以避免重复,可能会检查密钥或使用简单的布尔检查。
并请注意无用的过程,通过发信号通知另一个关于中止其搜索过程的线程,如果您只需要第一个创建的密钥,它就是业务的依赖。
答案 1 :(得分:0)
如果您无法修改更新/添加的来源以避免重复,那么您将不得不在某处创建一个阻塞点。目标只是以尽可能少的争用来做到这一点。
一种方法是使用请求队列,工作队列和ConcurrentHashMap进行查找。所有新请求都被添加到请求队列中,该队列由单个“网守”线程处理。网守可以一次接受一个请求或者排空队列并在循环中处理所有待处理的请求以减少该端的争用。
为了处理请求,网守确实在ConcurrentHashMap上放置了IfAfAsent。如果返回值为null,则可以将更新/插入请求添加到实际工作队列。如果该值已经在地图中,那么....请参阅下面的#2。实际上你可以使用超过1个网守,因为putIfAbsent是原子的,但它只会增加对HashMap的争用。看门人的实际处理时间非常短,以至于你不会通过在请求队列中投入更多的东西来获得任何东西。
工作队列线程将能够同时处理多个更新/插入,只要它们不修改同一记录即可。当工作队列线程完成处理请求时,它们会从ConcurrentHashMap中删除该值,以便网守知道再次修改该记录是安全的。
-
要考虑的一些事情:
1)您想如何定义可以同时进行的操作?它可能不应该散列整个请求,因为您不希望两个不同的请求同时修改同一个文档,对吗?
2)对于当前无法处理的请求,您应该怎么做,因为它们已经在队列中有重复(或修改相同文档的请求,如第1点)?把它们扔出去?将它们放在次要更新队列中,定期再次尝试?如果原始请求者的请求处于无限期持有模式,您如何回应原始请求者?
3)处理请求的顺序是否重要?