执行jmter tests ,直接用于本地GUI和非GUI调用,或者在服务器模式下运行时由RemoteJMeterEngineImpl启动
在JMeterEngineImpl中做了一部分的解释,可以结合着看
灵魂级变量,注意关键字volatile
private static volatile StandardJMeterEngine engine;
有两种构造函数,带参和不带参
public StandardJMeterEngine() {
this(null);
}
public StandardJMeterEngine(String host) {
this.host = host;
// Hack to allow external control
initSingletonEngine(this);
}
initSingletonEngine()、initSingletonEngine()、stopEngineNow()、stopEngine()略
根据threadName停止线程的执行:分两种情况立即停止和非立即停止,根据第二个参数的值决定
private static boolean stopThread(String threadName, boolean now) {
if (engine == null) {
return false;// e.g. not yet started
}
boolean wasStopped = false;
// ConcurrentHashMap does not need synch. here
for (AbstractThreadGroup threadGroup : engine.groups) {
wasStopped = wasStopped || threadGroup.stopThread(threadName, now);
}
return wasStopped;
}
ThreadGroup.stopThread及调用及具体实现参考代码如下
public boolean stopThread(String threadName, boolean now) {
for(Entry entry : allThreads.entrySet()) {
JMeterThread thrd = entry.getKey();
if (thrd.getThreadName().equals(threadName)) {
stopThread(thrd, entry.getValue(), now);
return true;
}
}
return false;
}
/**
* Hard Stop JMeterThread thrd and interrupt JVM Thread if interrupt is true
* @param jmeterThread {@link JMeterThread}
* @param jvmThread {@link Thread}
* @param interrupt Interrupt thread or not
*/
private void stopThread(JMeterThread jmeterThread, Thread jvmThread, boolean interrupt) {
jmeterThread.stop();
jmeterThread.interrupt(); // interrupt sampler if possible
if (interrupt && jvmThread != null) { // Bug 49734
jvmThread.interrupt(); // also interrupt JVM thread
}
}
参考 http://blog.csdn.net/yue530tomtom/article/details/78016823#t2
参考 http://blog.csdn.net/yue530tomtom/article/details/78016823#t3
移除线程组,在run方法里调用
private void removeThreadGroups(List> elements) {
Iterator> iter = elements.iterator();
while (iter.hasNext()) { // Can't use for loop here because we remove elements
Object item = iter.next();
if (item instanceof AbstractThreadGroup) {
iter.remove();
} else if (!(item instanceof TestElement)) {
iter.remove();
}
}
}
测试开始通知监听
private void notifyTestListenersOfStart(SearchByClass testListeners) {
for (TestStateListener tl : testListeners.getSearchResults()) {
if (tl instanceof TestBean) {
TestBeanHelper.prepare((TestElement) tl);
}
if (host == null) {
tl.testStarted();
} else {
tl.testStarted(host);
}
}
}
介绍本方法需要了解下TestStateListener
public interface TestStateListener {
void testStarted();
void testStarted(String host);
void testEnded();
void testEnded(String host);
}
testStarted:在测试开始之前调用
testEnded:在所有线程测试结束时调用一次
测试结束通知监听
private void notifyTestListenersOfEnd(SearchByClass testListeners) {
log.info("Notifying test listeners of end of test");
for (TestStateListener tl : testListeners.getSearchResults()) {
try {
if (host == null) {
tl.testEnded();
} else {
tl.testEnded(host);
}
} catch (Exception e) {
log.warn("Error encountered during shutdown of " + tl.toString(), e);
}
}
if (host != null) {
log.info("Test has ended on host " + host);
long now = System.currentTimeMillis();
System.out.println("Finished the test on host " + host + " @ " + new Date(now) + " (" + now + ")" // NOSONAR Intentional
+ (EXIT_AFTER_TEST ? " - exit requested." : ""));
if (EXIT_AFTER_TEST) {
exit();
}
}
active = false;
}
参考 http://blog.csdn.net/yue530tomtom/article/details/78016823#t5
实现runnable接口,主要操作AbstractThreadGroup中的方法
public static synchronized void startTest() {
if (testStart == 0) {
numberOfActiveThreads = 0;
testStart = System.currentTimeMillis();
JMeterUtils.setProperty("TESTSTART.MS",Long.toString(testStart));
}
}
public static synchronized void clearTotalThreads() {
totalThreads = 0;
numberOfThreadsStarted = 0;
numberOfThreadsFinished = 0;
}
try {
PreCompiler compiler = new PreCompiler();
test.traverse(compiler);
} catch (RuntimeException e) {
log.error("Error occurred compiling the tree:", e);
JMeterUtils.reportErrorToUser("Error occurred compiling the tree: - see log file", e);
return; // no point continuing
}
SearchByClass testListeners = new SearchByClass<>(TestStateListener.class); // TL-S&E
test.traverse(testListeners);
// Merge in any additional test listeners
// currently only used by the function parser
testListeners.getSearchResults().addAll(testList);
notifyTestListenersOfStart(testListeners);
private void notifyTestListenersOfStart(SearchByClass testListeners) {
for (TestStateListener tl : testListeners.getSearchResults()) {
if (tl instanceof TestBean) {
TestBeanHelper.prepare((TestElement) tl);
}
if (host == null) {
tl.testStarted();
} else {
tl.testStarted(host);
}
}
}
ListenerNotifier notifier = new ListenerNotifier();
if (setupIter.hasNext()) {
log.info("Starting setUp thread groups");
while (running && setupIter.hasNext()) {// for each setup thread group
AbstractThreadGroup group = setupIter.next();
groupCount++;
String groupName = group.getName();
log.info("Starting setUp ThreadGroup: " + groupCount + " : " + groupName);
startThreadGroup(group, groupCount, setupSearcher, testLevelElements, notifier);
if (serialized && setupIter.hasNext()) {
log.info("Waiting for setup thread group: " + groupName
+ " to finish before starting next setup group");
group.waitThreadsStopped();
}
}
log.info("Waiting for all setup thread groups to exit");
// wait for all Setup Threads To Exit
waitThreadsStopped();
log.info("All Setup Threads have ended");
groupCount = 0;
JMeterContextService.clearTotalThreads();
}
JMeterUtils.helpGC();
while (running && iter.hasNext()) {// for each thread group
AbstractThreadGroup group = iter.next();
// ignore Setup and Post here. We could have filtered the searcher.
// but then
// future Thread Group objects wouldn't execute.
if (group instanceof SetupThreadGroup || group instanceof PostThreadGroup) {
continue;
}
groupCount++;
String groupName = group.getName();
log.info("Starting ThreadGroup: " + groupCount + " : " + groupName);
startThreadGroup(group, groupCount, searcher, testLevelElements, notifier);
if (serialized && iter.hasNext()) {
log.info("Waiting for thread group: " + groupName + " to finish before starting next group");
group.waitThreadsStopped();
}
} // end of thread groups
if (groupCount == 0) { // No TGs found
log.info("No enabled thread groups found");
} else {
if (running) {
log.info("All thread groups have been started");
} else {
log.info("Test stopped - no more thread groups will be started");
}
}
// wait for all Test Threads To Exit
waitThreadsStopped();
if (postIter.hasNext()) {
groupCount = 0;
JMeterContextService.clearTotalThreads();
log.info("Starting tearDown thread groups");
if (mainGroups && !running) { // i.e. shutdown/stopped during main
// thread groups
running = shutdown && tearDownOnShutdown; // re-enable for
// tearDown if
// necessary
}
while (running && postIter.hasNext()) {// for each setup thread
// group
AbstractThreadGroup group = postIter.next();
groupCount++;
String groupName = group.getName();
log.info("Starting tearDown ThreadGroup: " + groupCount + " : " + groupName);
startThreadGroup(group, groupCount, postSearcher, testLevelElements, notifier);
if (serialized && postIter.hasNext()) {
log.info("Waiting for post thread group: " + groupName
+ " to finish before starting next post group");
group.waitThreadsStopped();
}
}
waitThreadsStopped(); // wait for Post threads to stop
}
notifyTestListenersOfEnd(testListeners);
JMeterContextService.endTest();
启动线程组,run方法中调用
private void startThreadGroup(AbstractThreadGroup group, int groupCount, SearchByClass> searcher,
List> testLevelElements, ListenerNotifier notifier) {
try {
int numThreads = group.getNumThreads();
JMeterContextService.addTotalThreads(numThreads);
boolean onErrorStopTest = group.getOnErrorStopTest();
boolean onErrorStopTestNow = group.getOnErrorStopTestNow();
boolean onErrorStopThread = group.getOnErrorStopThread();
boolean onErrorStartNextLoop = group.getOnErrorStartNextLoop();
String groupName = group.getName();
log.info("Starting " + numThreads + " threads for group " + groupName + ".");
if (onErrorStopTest) {
log.info("Test will stop on error");
} else if (onErrorStopTestNow) {
log.info("Test will stop abruptly on error");
} else if (onErrorStopThread) {
log.info("Thread will stop on error");
} else if (onErrorStartNextLoop) {
log.info("Thread will start next loop on error");
} else {
log.info("Thread will continue on error");
}
ListedHashTree threadGroupTree = (ListedHashTree) searcher.getSubTree(group);
threadGroupTree.add(group, testLevelElements);
groups.add(group);
group.start(groupCount, notifier, threadGroupTree, this);
} catch (JMeterStopTestException ex) { // NOSONAR Reported by log
JMeterUtils.reportErrorToUser("Error occurred starting thread group :" + group.getName()
+ ", error message:" + ex.getMessage() + ", \r\nsee log file for more details", ex);
return; // no point continuing
}
}
等待线程停止,run方法中调用
/**
* Wait for Group Threads to stop
*/
private void waitThreadsStopped() {
// ConcurrentHashMap does not need synch. here
for (AbstractThreadGroup threadGroup : groups) {
threadGroup.waitThreadsStopped();
}
}
/**
* Wait for all Group Threads to stop
*/
@Override
public void waitThreadsStopped() {
if (delayedStartup) {
waitThreadStopped(threadStarter);
}
for (Thread t : allThreads.values()) {
waitThreadStopped(t);
}
}
/**
* Wait for thread to stop
* @param thread Thread
*/
private void waitThreadStopped(Thread thread) {
if (thread != null) {
while (thread.isAlive()) {
try {
thread.join(WAIT_TO_DIE);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
学习备忘
原文连接 http://blog.csdn.net/yue530tomtom/article/details/78055365