Zoie源代码阅读----AsyncDataConsumer
这个类的关于consume() 和 flushBuffer()方法的等待调用比较绕逻辑 。
package proj.zoie.impl.indexing; import java.util.Collection; import java.util.LinkedList; import org.apache.log4j.Logger; import proj.zoie.api.DataConsumer; import proj.zoie.api.ZoieException; /** * 数据的消费者,由ZoieSystem来继承,实际的的数据消费者 ,由StreamDataProvider.start()方法启动的线程DataThread来调用 * 其中也有一个DataConsumer<V> _consumer, * @author cctv * @param <V> */ public class AsyncDataConsumer<V> implements DataConsumer<V> { private static final Logger log = Logger.getLogger(AsyncDataConsumer.class); private ConsumerThread _consumerThread; private DataConsumer<V> _consumer; private long _currentVersion; private long _bufferedVersion; private LinkedList<DataEvent<V>> _batch; private int _batchSize; public AsyncDataConsumer() { _currentVersion = -1L; _bufferedVersion = -1L; _batch = new LinkedList<DataEvent<V>>(); _batchSize = 1; // default _consumerThread = null; } //如果这个方法不调用,则不能启动消费的进程_consumerThread 。 public void start() { _consumerThread = new ConsumerThread(); _consumerThread.setDaemon(true); _consumerThread.start(); } public void stop() { _consumerThread.terminate(); } public void setDataConsumer(DataConsumer<V> consumer) { synchronized(this) { _consumer = consumer; } } public void setBatchSize(int batchSize) { synchronized(this) { _batchSize = Math.max(1, batchSize); } } public int getBatchSize() { synchronized(this) { return _batchSize; } } public int getCurrentBatchSize() { synchronized(this) { return (_batch != null ? _batch.size() : 0); } } public long getCurrentVersion() { synchronized(this) { return _currentVersion; } } public void flushEvents(long timeout) throws ZoieException { syncWthVersion(timeout, _bufferedVersion); } public void syncWthVersion(long timeInMillis, long version) throws ZoieException { long now = System.currentTimeMillis(); long due = now + timeInMillis; if(_consumerThread == null) throw new ZoieException("not running"); synchronized(this) { while(_currentVersion < version) { if(now >= due) { throw new ZoieException("sync timed out"); } try { this.wait(due - now); } catch(InterruptedException e) { log.warn(e.getMessage(), e); } now = System.currentTimeMillis(); } } } /** * 别的对象调用此方法将要消费的数据传递进来 。 * 该方法会判断LinkedList<DataEvent<V>> _batch中是否装满数据,若是装满,则休眠这个方法,然后会唤醒flushBuffer()去将_batch中数据消费完 */ @Override public void consume(Collection<DataEvent<V>> data) throws ZoieException { if (data == null || data.size() == 0) return; synchronized(this) { while(_batch.size() >= _batchSize) //如果数据满了,则休眠自己一会让其他的方法(flushBuffer())去flush掉数据到真正的ZoieSystem中,等使用完数据该方法会继续执行下去 { if(_consumerThread == null || !_consumerThread.isAlive() || _consumerThread._stop) { throw new ZoieException("consumer thread has stopped"); } try { this.wait(); } catch (InterruptedException e) { } } for(DataEvent<V> event : data) { _bufferedVersion = Math.max(_bufferedVersion, event.getVersion()); _batch.add(event); } this.notifyAll(); // wake up the thread waiting in flushBuffer() } } //该对象启动时自动创建一个守护进程,然后不停的来掉这个方法 /** * 该方法会不停的被一个守护进程ConsumerThread来调用,每次取"吃掉"外界传来的在LinkedList<DataEvent<V>> _batch中存的数据, * 若是调用时_batch中没有数据,则等待该方法,唤醒consume()去装数据,装完一次数据后在唤醒自己,去“吃掉”这部分数据 */ protected final void flushBuffer() { long version; LinkedList<DataEvent<V>> currentBatch; synchronized(this) { while(_batch.size() == 0) //如果等于0的话,则休眠自己,让别的线程(consume())使用,去装数据 ,装完数据会后会继续往下执行 { if(_consumerThread._stop) return; try { this.wait(); } catch (InterruptedException e) { } } version = Math.max(_currentVersion, _bufferedVersion); currentBatch = _batch; _batch = new LinkedList<DataEvent<V>>(); this.notifyAll(); // wake up the thread waiting in addEventToBuffer() } //消费数据 if(_consumer != null) { try { _consumer.consume(currentBatch); } catch (Exception e) { log.error(e.getMessage(), e); } } synchronized(this) { _currentVersion = version; this.notifyAll(); // wake up the thread waiting in syncWthVersion() } } //内启动的线程,不停的调用父对象的flushBuffer() private final class ConsumerThread extends IndexingThread { boolean _stop = false; ConsumerThread() { super("ConsumerThread"); } public void terminate() { _stop = true; synchronized(AsyncDataConsumer.this) { AsyncDataConsumer.this.notifyAll(); } } public void run() { while(!_stop) { flushBuffer(); } } } }
该类数据实际做索引的对象的一个数据中专站的形式,存储数据并中转,自己并不实际消费数据 。