Java 生产者和消费者分批生产;第二批';直到上一批货完成,我才来
我试图实现一种机制,其中可运行者既是生产者又是消费者 情况是- 我需要从数据库中批量读取记录,并对其进行处理。我正在尝试使用生产者-消费者模式。我得到一批,我处理。获取批处理、进程。每当它看到队列为空时,就会得到一个批处理。其中一条线去拿东西。但问题是,我无法标记获取用于处理的记录,这是我的限制。因此,如果我们在完全提交前一批之前获取下一批,我可能会再次获取相同的记录。因此,我需要能够在拉动另一个之前完全提交前一个。我不知道在这里该怎么办。我试着保持已获取的一个的计数,然后保持我的get,直到达到该计数 处理这种情况的最好方法是什么?以块的形式处理数据库中的记录——我在这里遇到的最大限制是,我无法标记已拾取的记录。所以,我想按顺序进行批处理。但是批处理应该在内部使用多线程Java 生产者和消费者分批生产;第二批';直到上一批货完成,我才来,java,multithreading,batch-processing,producer-consumer,Java,Multithreading,Batch Processing,Producer Consumer,我试图实现一种机制,其中可运行者既是生产者又是消费者 情况是- 我需要从数据库中批量读取记录,并对其进行处理。我正在尝试使用生产者-消费者模式。我得到一批,我处理。获取批处理、进程。每当它看到队列为空时,就会得到一个批处理。其中一条线去拿东西。但问题是,我无法标记获取用于处理的记录,这是我的限制。因此,如果我们在完全提交前一批之前获取下一批,我可能会再次获取相同的记录。因此,我需要能够在拉动另一个之前完全提交前一个。我不知道在这里该怎么办。我试着保持已获取的一个的计数,然后保持我的get,直到达
public class DealStoreEnricher extends AsyncExecutionSupport {
private static final int BATCH_SIZE = 5000;
private static final Log log = LogFactory.getLog(DealStoreEnricher.class);
private final DealEnricher dealEnricher;
private int concurrency = 10;
private final BlockingQueue<QueryDealRecord> dealsToBeEnrichedQueue;
private final BlockingQueue<QueryDealRecord> dealsEnrichedQueue;
private DealStore dealStore;
private ExtractorProcess extractorProcess;
ExecutorService executor;
public DealStoreEnricher(DealEnricher dealEnricher, DealStore dealStore, ExtractorProcess extractorProcess) {
this.dealEnricher = dealEnricher;
this.dealStore = dealStore;
this.extractorProcess = extractorProcess;
dealsToBeEnrichedQueue = new LinkedBlockingQueue<QueryDealRecord>();
dealsEnrichedQueue = new LinkedBlockingQueue<QueryDealRecord>(BATCH_SIZE * 3);
}
public ExtractorProcess getExtractorProcess() {
return extractorProcess;
}
public DealEnricher getDealEnricher() {
return dealEnricher;
}
public int getConcurrency() {
return concurrency;
}
public void setConcurrency(int concurrency) {
this.concurrency = concurrency;
}
public DealStore getDealStore() {
return dealStore;
}
public DealStoreEnricher withConcurrency(int concurrency) {
setConcurrency(concurrency);
return this;
}
@Override
public void start() {
super.start();
executor = Executors.newFixedThreadPool(getConcurrency());
for (int i = 0; i < getConcurrency(); i++)
executor.submit(new Runnable() {
public void run() {
try {
QueryDealRecord record = null;
while ((record = get()) != null && !isCancelled()) {
try {
update(getDealEnricher().enrich(record));
processed.incrementAndGet();
} catch (Exception e) {
failures.incrementAndGet();
log.error("Failed to process deal: " + record.getTradeId(), e);
}
}
} catch (InterruptedException e) {
setCancelled();
}
}
});
executor.shutdown();
}
protected void update(QueryDealRecord enrichedRecord) {
dealsEnrichedQueue.add(enrichedRecord);
if (batchComplete()) {
List<QueryDealRecord> enrichedRecordsBatch = new ArrayList<QueryDealRecord>();
synchronized (this) {
dealsEnrichedQueue.drainTo(enrichedRecordsBatch);
}
if (!enrichedRecordsBatch.isEmpty())
updateTheDatabase(enrichedRecordsBatch);
}
}
private void updateTheDatabase(List<QueryDealRecord> enrichedRecordsBatch) {
getDealStore().insertEnrichedData(enrichedRecordsBatch, getExtractorProcess());
}
/**
* @return true if processed records have reached the batch size or there's
* nothing to be processed now.
*/
private boolean batchComplete() {
return dealsEnrichedQueue.size() >= BATCH_SIZE || dealsToBeEnrichedQueue.isEmpty();
}
/**
* Gets an item from the queue of things to be enriched
*
* @return {@linkplain QueryDealRecord} to be enriched
* @throws InterruptedException
*/
protected synchronized QueryDealRecord get() throws InterruptedException {
try {
if (!dealsToBeEnrichedQueue.isEmpty()) {
return dealsToBeEnrichedQueue.take();
} else {
List<QueryDealRecord> records = getNextBatchToBeProcessed();
if (!records.isEmpty()) {
dealsToBeEnrichedQueue.addAll(records);
return dealsToBeEnrichedQueue.take();
}
}
} catch (InterruptedException ie) {
throw new UnRecoverableException("Unable to retrieve QueryDealRecord", ie);
}
return null;
}
private List<QueryDealRecord> getNextBatchToBeProcessed() {
List<QueryDealRecord> recordsThatNeedEnriching = getDealStore().getTheRecordsThatNeedEnriching(getExtractorProcess());
return recordsThatNeedEnriching;
}
@Override
public void stop() {
super.stop();
if (executor != null)
executor.shutdownNow();
}
@Override
public boolean await() throws InterruptedException {
return executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS) && !isCancelled() && complete();
}
@Override
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
return executor.awaitTermination(timeout, unit) && !isCancelled() && complete();
}
private boolean complete() {
setCompleted();
return true;
}
公共类DealStoreEnricher扩展了AsyncExecutionSupport{
专用静态最终整数批大小=5000;
私有静态最终日志日志=LogFactory.getLog(DealStoreEnricher.class);
私人最终DealEnricher DealEnricher;
私有int并发=10;
私有最终阻塞队列dealsToBeEnrichedQueue;
私有最终阻塞队列dealsEnrichedQueue;
私人交易商店;
私有提取器进程提取器进程;
执行人服务执行人;
公共DealStoreEnricher(DealEnricher DealEnricher,DealStore DealStore,提取器进程提取器进程){
this.dealEnricher=dealEnricher;
this.dealStore=dealStore;
this.extractorProcess=extractorProcess;
dealsToBeEnrichedQueue=新建LinkedBlockingQueue();
dealsEnrichedQueue=新的LinkedBlockingQueue(批量大小*3);
}
公共提取器进程getExtractor进程(){
返回提取器进程;
}
公共DealEnricher getDealEnricher(){
返回式脱包器;
}
公共int getConcurrency(){
返回并发;
}
公共void setConcurrency(int concurrency){
this.concurrency=并发;
}
公共DealStore getDealStore(){
退货商店;
}
具有并发性的公共DealStoreEnricher(int并发性){
setConcurrency(并发);
归还这个;
}
@凌驾
公开作废开始(){
super.start();
executor=Executors.newFixedThreadPool(getConcurrency());
for(int i=0;i=BATCH_size | | dealsToBeEnrichedQueue.isEmpty();
}
/**
*从要充实的内容队列中获取项目
*
*@return{@linkplain QueryDealRecord}将被充实
*@抛出中断异常
*/
受保护的同步QueryDealRecord get()引发InterruptedException{
试一试{
如果(!dealsToBeEnrichedQueue.isEmpty()){
return dealsToBeEnrichedQueue.take();
}否则{
列表记录=getNextBatchToBeProcessed();
如果(!records.isEmpty()){
dealsToBeEnrichedQueue.addAll(记录);
return dealsToBeEnrichedQueue.take();
}
}
}捕获(中断异常ie){
抛出新的不可恢复异常(“无法检索QueryDealRecord”,即);
}
返回null;
}
私有列表getNextBatchToBeProcessed(){
List RecordsThatNeedFurning=getDealStore().GetTheRecordsThatNeedFurning(getExtractorProcess());
返回所需的记录;
}
@凌驾
公共停车场(){
super.stop();
if(executor!=null)
执行者。关机现在();
}
@凌驾
public boolean await()抛出InterruptedException{
返回executor.awaitTermination(Long.MAX_值,TimeUnit.SECONDS)和&!isCancelled()和&complete();
}
@凌驾
公共布尔等待(长超时,时间单位)抛出InterruptedException{
返回执行器。等待终止(超时,单位)&&!isCancelled()&&complete();
}
私有布尔完成(){
setCompleted();
返回true;
}
}您已经在使用a-它可以为您完成所有工作
但是,您使用了错误的方法addAll()
将新元素添加到队列中。如果队列不能接受元素,该方法将抛出异常。相反,您应该使用put()
,因为这是阻塞方法
BlockingQueue blockingQueue = ...;
Semapore semaphore = new Semaphore(1);
Batch batch = db.getBatch();
semaphore.acquire(); // wait until previous batch completes
blockingQueue.add(batch);
for(;;){
Batch batch = blockingQueue.take();
doBatchUpdate(batch);
semaphore.release(); // tell next batch to run
}