大家知道,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对象也要单例喔,不然上面代码也全部作废,达不到预想效果,不信你可以试试。