Lucene之IndexWriter、IndexReader保证唯一实例(备忘)

大家知道,lucene中的IndexWriter和IndexReader都是线程安全的类,但是不能出现多多线程绑定多个实例的情况。因此很有必要保证IndexWriter和IndexReader全局只有一个实例子。我们首先写一个类,让他来保证全局只有一个实例,类的接口如下:

1 public interface LuceneManager {
2 public IndexWriter getIndexWriter() throws CorruptIndexException, LockObtainFailedException, IOException;
3 public IndexReader getIndexReader() throws CorruptIndexException, IOException;
4 public void closeIndexWriter() throws IOException;
5 public void closeIndexReader() throws IOException;
6 public void closeAll() throws IOException;
7 }

接口实现类代码如下,主要看看它如何保证只有一个实例:

 1 package com.geostar.poi.support.lucene;
2
3 import java.io.File;
4 import java.io.IOException;
5
6 import org.apache.log4j.Logger;
7 import org.apache.lucene.analysis.Analyzer;
8 import org.apache.lucene.analysis.standard.StandardAnalyzer;
9 import org.apache.lucene.index.CorruptIndexException;
10 import org.apache.lucene.index.IndexReader;
11 import org.apache.lucene.index.IndexWriter;
12 import org.apache.lucene.index.IndexWriter.MaxFieldLength;
13 import org.apache.lucene.store.FSDirectory;
14 import org.apache.lucene.store.LockObtainFailedException;
15 import org.apache.lucene.util.Version;
16
17 import com.geostar.poi.support.POIConfig;
18
19 public class POILuceneManager implements LuceneManager{
20 private IndexWriter indexWriter=null;
21 private IndexReader indexReader=null;
22 //------lock 1
23 private Object lock_w=new Object();
24 //------lock 2
25 private Object lock_r=new Object();
26
27 private Logger logger=Logger.getLogger(POILuceneManager.class);
28 @Override
29 public IndexWriter getIndexWriter() throws CorruptIndexException, LockObtainFailedException, IOException {
30 synchronized(lock_w){
31 if(indexWriter==null){
32 System.out.println("创建对象");
33 if(IndexWriter.isLocked(FSDirectory.open(new File(POIConfig.DEFULT_POI_LUCENNE_INDEX_PATH)))){
34 IndexWriter.unlock(FSDirectory.open(new File(POIConfig.DEFULT_POI_LUCENNE_INDEX_PATH)));
35 };
36 Analyzer any=new StandardAnalyzer(Version.LUCENE_CURRENT);
37 indexWriter=new IndexWriter(FSDirectory.open(new File(POIConfig.DEFULT_POI_LUCENNE_INDEX_PATH)),any,MaxFieldLength.UNLIMITED );
38 };
39
40 }
41 return indexWriter;
42 }
43
44 @Override
45 public IndexReader getIndexReader() throws CorruptIndexException, IOException {
46 synchronized (lock_r) {
47 if(indexReader==null){
48 indexReader=IndexReader.open(FSDirectory.open(new File(POIConfig.DEFULT_POI_LUCENNE_INDEX_PATH)));
49 };
50 }
51 return indexReader;
52 }
53
54 @Override
55 public void closeIndexWriter() throws IOException {
56 // TODO Auto-generated method stub
57 //synchronized (lock_w) {
58 if(this.indexWriter!=null){
59 this.indexWriter.close();
60 };
61 //}
62
63 }
64
65 @Override
66 public void closeIndexReader() throws IOException {
67 // TODO Auto-generated method stub
68 //synchronized (lock_r) {
69 if(this.indexReader!=null){
70 this.indexReader.close();
71 };
72 //}
73
74
75 }
76
77 @Override
78 public void closeAll() throws IOException {
79 // TODO Auto-generated method stub
80 this.closeIndexReader();
81 this.closeIndexWriter();
82
83 }
84
85 }

其中的synchronized代码块很重要,它保证只能创造一个IndexWriter实例。为了测试它能不能达到我们要的结果,我来写一个测试类。

测试类代码如下:

 1 package com.geostar.poi.support;
2
3 import java.io.IOException;
4
5 import org.apache.lucene.index.CorruptIndexException;
6 import org.apache.lucene.index.IndexWriter;
7 import org.apache.lucene.store.LockObtainFailedException;
8
9 import com.geostar.poi.support.lucene.LuceneManager;
10 import com.geostar.poi.support.lucene.POILuceneManager;
11
12 public class LuceneThreadTest {
13
14 /**
15 * @param args
16 */
17 public static void main(String[] args) {
18 final LuceneManager manager=new POILuceneManager();
19 for(int i=0;i<100;i++){
20 new Thread(new Runnable() {
21
22 @Override
23 public void run() {
24 try {
25 Thread.currentThread().sleep(500);
26 } catch (InterruptedException e) {
27 // TODO Auto-generated catch block
28 e.printStackTrace();
29 }
30
31
32 try {
33 IndexWriter writer=manager.getIndexWriter();
34 } catch (CorruptIndexException e) {
35 // TODO Auto-generated catch block
36 e.printStackTrace();
37 } catch (LockObtainFailedException e) {
38 // TODO Auto-generated catch block
39 e.printStackTrace();
40 } catch (IOException e) {
41 // TODO Auto-generated catch block
42 e.printStackTrace();
43 }finally{
44 try {
45 manager.closeAll();
46 } catch (IOException e) {
47 // TODO Auto-generated catch block
48 e.printStackTrace();
49 }
50 }
51
52 }
53 }).start();
54 };
55 }
56
57 }

ok ,运行代码,只见后台出现以下信息:

log4j:WARN No such property [maxBackupIndex] in org.apache.log4j.DailyRollingFileAppender.
log4j:WARN No such property [maxFileSize] in org.apache.log4j.DailyRollingFileAppender.
创建对象

看来这个结果还是比较正常,每个线程中执行getIndexWriter方法,获得对象之后,然后关闭对象,关闭文件锁。那么我们将PoiLuceneManager中synchronized代码块注释掉,再看看效果如何,控制台信息如下:

log4j:WARN No such property [maxBackupIndex] in org.apache.log4j.DailyRollingFileAppender.
log4j:WARN No such property [maxFileSize] in org.apache.log4j.DailyRollingFileAppender.
创建对象
创建对象
创建对象
创建对象
创建对象
org.apache.lucene.store.LockObtainFailedException: Lock obtain timed out: NativeFSLock@C:\CommonServices\poi\write.lock
	at org.apache.lucene.store.Lock.obtain(Lock.java:84)
	at org.apache.lucene.index.IndexWriter.init(IndexWriter.java:1041)
	at org.apache.lucene.index.IndexWriter.init(IndexWriter.java:1016)
	at org.apache.lucene.index.IndexWriter.<init>(IndexWriter.java:887)
	at com.geostar.poi.support.lucene.POILuceneManager.getIndexWriter(POILuceneManager.java:37)
	at com.geostar.poi.support.LuceneThreadTest$1.run(LuceneThreadTest.java:33)
	at java.lang.Thread.run(Thread.java:619)
org.apache.lucene.store.LockObtainFailedException: Lock obtain timed out: NativeFSLock@C:\CommonServices\poi\write.lock
	at org.apache.lucene.store.Lock.obtain(Lock.java:84)
	at org.apache.lucene.index.IndexWriter.init(IndexWriter.java:1041)
	at org.apache.lucene.index.IndexWriter.init(IndexWriter.java:1016)
	at org.apache.lucene.index.IndexWriter.<init>(IndexWriter.java:887)
	at com.geostar.poi.support.lucene.POILuceneManager.getIndexWriter(POILuceneManager.java:37)
	at com.geostar.poi.support.LuceneThreadTest$1.run(LuceneThreadTest.java:33)
	at java.lang.Thread.run(Thread.java:619)
org.apache.lucene.store.LockObtainFailedException: Lock obtain timed out: NativeFSLock@C:\CommonServices\poi\write.lock
	at org.apache.lucene.store.Lock.obtain(Lock.java:84)
	at org.apache.lucene.index.IndexWriter.init(IndexWriter.java:1041)
	at org.apache.lucene.index.IndexWriter.init(IndexWriter.java:1016)
	at org.apache.lucene.index.IndexWriter.<init>(IndexWriter.java:887)
	at com.geostar.poi.support.lucene.POILuceneManager.getIndexWriter(POILuceneManager.java:37)
	at com.geostar.poi.support.LuceneThreadTest$1.run(LuceneThreadTest.java:33)
	at java.lang.Thread.run(Thread.java:619)

 但看打印多个“创建对象”已经知道此方法无法保证只能创建一个IndexWriter对象,同时错误信息也表示多个对象锁冲突,并发出现问题。

综上,IndexWriter是线程安全对象,但是不容许多线程操作多个IndexWriter实例对象,IndexReader亦然。当然也要记住LuceneManager对象也要单例喔,不然上面代码也全部作废,达不到预想效果,不信你可以试试。

 



 

你可能感兴趣的:(Lucene)