org.databene.task.runner.MultiThreadedTaskRunner Maven / Gradle / Ivy
Go to download
benerator is a framework for creating realistic and valid high-volume test data, used for
testing (unit/integration/load) and showcase setup.
Metadata constraints are imported from systems and/or configuration files. Data can imported from
and exported to files and systems, anonymized or generated from scratch. Domain packages provide
reusable generators for creating domain-specific data as names and addresses internationalizable
in language and region. It is strongly customizable with plugins and configuration options.
/*
* (c) Copyright 2010 by Volker Bergmann. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted under the terms of the
* GNU General Public License (GPL).
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
* REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
* HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.databene.task.runner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicLong;
import org.databene.commons.BeanUtil;
import org.databene.commons.ConfigurationError;
import org.databene.commons.Context;
import org.databene.commons.ErrorHandler;
import org.databene.contiperf.PerformanceTracker;
import org.databene.task.StateTrackingTaskProxy;
import org.databene.task.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* {@link TaskRunner} implementation that is able to execute a {@link Task} with multiple threads.
* Created: 27.03.2010 14:12:16
* @since 0.6.0
* @author Volker Bergmann
*/
public class MultiThreadedTaskRunner implements TaskRunner {
private static final Logger logger = LoggerFactory.getLogger(MultiThreadedTaskRunner.class);
protected Task target;
private int threadCount;
protected Context context;
private ExecutorService executorService;
protected ErrorHandler errorHandler;
private PerformanceTracker tracker;
public MultiThreadedTaskRunner(Task target, int threadCount, Context context, ExecutorService executorService,
ErrorHandler errorHandler, PerformanceTracker tracker) {
this.target = target;
this.threadCount = threadCount;
this.context = context;
this.executorService = executorService;
this.errorHandler = errorHandler;
this.tracker = tracker;
}
public long run(Long maxInvocationCount) {
AtomicLong counter = new AtomicLong();
int maxLoopsPerPage = (int)((maxInvocationCount + threadCount - 1) / threadCount);
int shorterLoops = (int)(threadCount * maxLoopsPerPage - maxInvocationCount);
boolean threadSafe = target.isThreadSafe();
boolean parallelizable = target.isParallelizable();
// create threads for a page
CountDownLatch latch = new CountDownLatch(threadCount);
for (int threadNo = 0; threadNo < threadCount; threadNo++) {
int loopSize = maxLoopsPerPage;
if (maxInvocationCount >= 0 && threadNo >= threadCount - shorterLoops)
loopSize--;
if (loopSize > 0) {
Task task = target;
if (threadCount > 1 && !threadSafe) {
if (parallelizable) {
task = BeanUtil.clone(task);
} else
throw new ConfigurationError("Since the task is not marked as thread-safe," +
"it must either be used in a single thread or be parallelizable.");
}
if (tracker != null)
task = ((StateTrackingTaskProxy>) task).clone();
TaskRunnable runner = new TaskRunnable(loopSize, counter, latch, !threadSafe);
executorService.execute(runner);
} else
latch.countDown();
}
if (logger.isDebugEnabled())
logger.debug("Waiting for end of page on " + target.getTaskName() + "...");
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (threadSafe) // TODO v0.7 call pageFinished only if it was actually run in shared mode
target.pageFinished();
return counter.get();
}
public class TaskRunnable implements Runnable {
private CountDownLatch latch;
private boolean page;
private long requestedInvocationCount;
private AtomicLong counter;
public TaskRunnable(long requestedInvocationCount, AtomicLong counter, CountDownLatch latch, boolean page) {
this.latch = latch;
this.page = page;
this.requestedInvocationCount = requestedInvocationCount;
this.counter = counter;
}
public void run() {
try {
long count = SingleThreadedTaskRunner.runWithoutPage(target, requestedInvocationCount, context, errorHandler);
counter.addAndGet(count);
if (page)
target.pageFinished();
} finally {
if (latch != null)
latch.countDown();
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy