当前位置:网站首页>性能工具之JMeter5.0核心类StandardJMeterEngine源码分析
性能工具之JMeter5.0核心类StandardJMeterEngine源码分析
2021-10-22 10:28:59 【高楼(Zee)】
概述
JMeter 默认单机压测引擎,运行 JMeter 测试,直接用于本地 GUI 和非 GUI 调用,或者RemoteJMeterEngineImpl 在服务器模式下运行时启动。
API地址:https://jmeter.apache.org/api/org/apache/jmeter/engine/StandardJMeterEngine.html
工程位置
逻辑关系
简要解读:
- HashTree是依赖的数据结构;
- SearchByClass 用来查找 HashTree 中的所有节点,并把节点实例化为真正的对象,例如图中TestPlan/ThreadGroup/JavaSampler/ResultCollector 在 HashTree 中本来都是只是配置,全部通过 SearchByClass 实例化的;
- 实例化出来的对象如果是 TestStateListener 类型,则会在有生命周期的函数回调,测试前调 testStarted,结束掉 testEnded, 比如 ResultCollector是该类型的一种,在结束的时候回调 testEnded 方法完成 report 的写入;
- PreCompiler 用来解析 Arguments, 把 TestPlan 节点中配置的参数作为JMeterVariables 加入到测试线程上线文中;
- ThreadGroup 用来用来管理一组线程,包括线程的个数/启动/关闭等;StopTest 作为其内部类对外不可见,作为一个 Runnable,作用是异步停止测试,stopTest方法也是通过该内部类实现的。
主要变量
注意关键字 volatile
1. // 灵魂级变量,注意关键字volatile
2. private static volatile StandardJMeterEngine engine;
- 1.
- 2.
- 3.
构造函数
有两种构造函数,带参和不带参
1. // 不带参构造函数
2. public StandardJMeterEngine() {
3. this(null);
4. }
5.
6. // 带参构造函数
7. public StandardJMeterEngine(String host) {
8. this.host = host;
9. // Hack to allow external control
10. initSingletonEngine(this);
11. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
主要方法
askThreadsToStop
清洁关闭,即等待当前运行的采样器结束
1. /**
2. * Clean shutdown ie, wait for end of current running samplers
3. */
4. public void askThreadsToStop() {
5. if (engine != null) { // Will be null if StopTest thread has started
6. engine.stopTest(false);
7. }
8. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
reset
JMeterEngine 如果运行则停止
1. // 重置。在StandardJMeterEngine中就是直接调用stopTest(true).
2. @Override
3. public void reset() {
4. if (running) {
5. stopTest();
6. }
7. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
configure(HashTree testTree)
配置引擎,HashTree 是 JMeter 执行测试依赖的数据结构,configure 在执行测试之前进行配置测试数据。
1. // HashTree是JMeter执行测试依赖的数据结构,configure在执行测试之前进行配置测试数据
2. // 从HashTree中解析出TestPlan, 获取TestPlan的serialized和tearDownOnShutdown并保存为local属性,同时把整个HashTree也保存到local。
3. // StandardJMeterEngine依赖线程组ThreadGroup, 一个测试中可能会有多个线程组,如果serialized为true,则StandardJMeterEngine会串行的去执行这些线程组,每启动一个ThreadGroup主线程都会等它结束;否则就并行执行所有的线程组。
4. // tearDownOnShutdown与PostThreadGroup配合使用的,这个Special Thread Group专门用来做清理工作
5.
6. @Override
7. public void configure(HashTree testTree) {
8. // Is testplan serialised?
9. SearchByClass<TestPlan> testPlan = new SearchByClass<>(TestPlan.class);
10. testTree.traverse(testPlan);
11. Object[] plan = testPlan.getSearchResults().toArray();
12. if (plan.length == 0) {
13. throw new IllegalStateException("Could not find the TestPlan class!");
14. }
15. TestPlan tp = (TestPlan) plan[0];
16. serialized = tp.isSerialized();
17. tearDownOnShutdown = tp.isTearDownOnShutdown();
18. active = true;
19. test = testTree;
20. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
exit
远程退出由 RemoteJMeterEngineImpl.rexit() 和notifyTestListenersOfEnd() 调用 iff exitAfterTest 为 true; 反过来,run( ) 方法调用,也调用 StopTest 类
1. /**
2. * Remote exit
3. * Called by RemoteJMeterEngineImpl.rexit()
4. * and by notifyTestListenersOfEnd() iff exitAfterTest is true;
5. * in turn that is called by the run() method and the StopTest class
6. * also called
7. *
8. * 是为Remote Test准备的
9. * 如果当前的测试是从一个客户端的JMeter执行远程JMeterEngine的remote samples,则应该调用该exit()方法来关闭远程的测试
10. * 被RemoteJMeterEngineImpl.rexit()调用和exitAfterTest为真时被notifyTestListenersOfEnd()调用
11. */
12. @Override
13. public void exit() {
14. ClientJMeterEngine.tidyRMI(log); // This should be enough to allow server to exit.
15. if (REMOTE_SYSTEM_EXIT) { // default is false
16. log.warn("About to run System.exit(0) on {}", host);
17. // Needs to be run in a separate thread to allow RMI call to return OK
18. Thread t = new Thread() {
19. @Override
20. public void run() {
21. pause(1000); // Allow RMI to complete
22. log.info("Bye from {}", host);
23. System.out.println("Bye from "+host); // NOSONAR Intentional
24. System.exit(0); // NOSONAR Intentional
25. }
26. };
27. t.start();
28. }
29. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
isActive
isActive 在测试中 JMeterEngine 返回值:
boolean 用于显示引擎是否处于活动状态的标志(在测试运行时为true)。在测试结束时设置为 false。
1. /**
2. * 引擎是否有效的标识,在测试结束时设为false
3. * 在confgiure()的时候设该值为true,在执行完测试(指的是该JMeterEngine所有ThreadGroup)之后设置为false。
4. * 如果active==true,则说明该JMeterEngine已经配置完测试并且还没执行完,我们不能再进行configure或者runTest了;
5. * 若active == false, 则该JMeterEngine是空闲的,我们可以重新配置HashTree,执行新的测试.
6. *
7. * @return
8. */
9.
10. @Override
11. public boolean isActive() {
12. return active;
13. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
engine
操作 engine,initSingletonEngine()、initSingletonEngine()、stopEngineNow()、stopEngine
1. /**
2. * Set the shared engine
3. * 操作 engine,initSingletonEngine()、initSingletonEngine()、stopEngineNow()、stopEngine
4. * @param standardJMeterEngine
5. */
6. private static void initSingletonEngine(StandardJMeterEngine standardJMeterEngine) {
7. StandardJMeterEngine.engine = standardJMeterEngine;
8. }
9.
10. public static void stopEngineNow() {
11. if (engine != null) {// May be null if called from Unit test
12. engine.stopTest(true);
13. }
14. }
15.
16. public static void stopEngine() {
17. if (engine != null) { // May be null if called from Unit test
18. engine.stopTest(false);
19. }
20. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
run
run(),启动测试。
JMeterContextService 清零:numberOfActiveThreads=0, 重置 testStart时间
1. JMeterContextService.startTest();
- 1.
JMeterContextService.startTest():
1. /**
2. * Method is called by the JMeterEngine class when a test run is started.
3. * Zeroes numberOfActiveThreads.
4. * Saves current time in a field and in the JMeter property "TESTSTART.MS"
5. */
6. public static synchronized void startTest() {
7. if (testStart == 0) {
8. numberOfActiveThreads = 0;
9. testStart = System.currentTimeMillis();
10. JMeterUtils.setProperty("TESTSTART.MS",Long.toString(testStart));// $NON-NLS-1$
11. }
12. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
PreCompiler the Tashree,见上面的简要解读
1. try {
2. PreCompiler compiler = new PreCompiler();
3. test.traverse(compiler);
4. } catch (RuntimeException e) {
5. log.error("Error occurred compiling the tree:", e);
6. JMeterUtils.reportErrorToUser("Error occurred compiling the tree: - see log file", e);
7. return; // no point continuing
8. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
利用 SearchByClass 解析所有 TestStateListener 加入到 testList 中
1. SearchByClass<TestStateListener> testListeners = new SearchByClass<>(TestStateListener.class); // TL-S&E
2. test.traverse(testListeners);
3. // Merge in any additional test listeners
4. // currently only used by the function parser
5. testListeners.getSearchResults().addAll(testList);
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 触发上一步中解析的 testListener 的 testStarted 方法:ResultCollector 会递增 instanceCount,初始化 fileOutput;TestPlan 会设置 FileServer 的basedir,添加 classpath; JavaSampler 会初始化真正要跑的AbstractJavaSamplerClient 类;
- 利用 SearchByClass 解析所有 ThreadGroup(包括SetupThreadGroup,ThreadGroup, PostThreadGroup)
1. notifyTestListenersOfStart(testListeners);
2.
3. private void notifyTestListenersOfStart(SearchByClass<TestStateListener> testListeners) {
4. for (TestStateListener tl : testListeners.getSearchResults()) {
5. if (tl instanceof TestBean) {
6. TestBeanHelper.prepare((TestElement) tl);
7. }
8. if (host == null) {
9. tl.testStarted();
10. } else {
11. tl.testStarted(host);
12. }
13. }
14. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
实例化一个 ListenerNotifier 实例,用来通知事件发生
1. ListenerNotifier notifier = new ListenerNotifier();
- 1.
启动所有 SetupThreadGroup (一般情况下没有 SetupThreadGroup )并等待到都结束
1. if (setupIter.hasNext()) {
2. log.info("Starting setUp thread groups");
3. while (running && setupIter.hasNext()) {// for each setup thread group
4. AbstractThreadGroup group = setupIter.next();
5. groupCount++;
6. String groupName = group.getName();
7. log.info("Starting setUp ThreadGroup: " + groupCount + " : " + groupName);
8. startThreadGroup(group, groupCount, setupSearcher, testLevelElements, notifier);
9. if (serialized && setupIter.hasNext()) {
10. log.info("Waiting for setup thread group: " + groupName
11. + " to finish before starting next setup group");
12. group.waitThreadsStopped();
13. }
14. }
15. log.info("Waiting for all setup thread groups to exit");
16. // wait for all Setup Threads To Exit
17. waitThreadsStopped();
18. log.info("All Setup Threads have ended");
19. groupCount = 0;
20. JMeterContextService.clearTotalThreads();
21. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
进行一次 gc 后 开始跑真正的测试,即启动所有的 ThreadGroup,这里会检查 serialized 属性,用来判断是否这些 ThreadGroup 串行执行
1. JMeterUtils.helpGC();
- 1.
等待所有的ThreadGroup结束
1. while (running && iter.hasNext()) {// for each thread group
2. AbstractThreadGroup group = iter.next();
3. // ignore Setup and Post here. We could have filtered the searcher.
4. // but then
5. // future Thread Group objects wouldn't execute.
6. if (group instanceof SetupThreadGroup || group instanceof PostThreadGroup) {
7. continue;
8. }
9. groupCount++;
10. String groupName = group.getName();
11. log.info("Starting ThreadGroup: " + groupCount + " : " + groupName);
12. startThreadGroup(group, groupCount, searcher, testLevelElements, notifier);
13. if (serialized && iter.hasNext()) {
14. log.info("Waiting for thread group: " + groupName + " to finish before starting next group");
15. group.waitThreadsStopped();
16. }
17. } // end of thread groups
18. if (groupCount == 0) { // No TGs found
19. log.info("No enabled thread groups found");
20. } else {
21. if (running) {
22. log.info("All thread groups have been started");
23. } else {
24. log.info("Test stopped - no more thread groups will be started");
25. }
26. }
27.
28. // wait for all Test Threads To Exit
29. waitThreadsStopped();
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
若有 PostThreadGroup(一般没有),执行所有的 PostThreadGroup 并等待至所有 PostThreadGroup 结束
1. if (postIter.hasNext()) {
2. groupCount = 0;
3. JMeterContextService.clearTotalThreads();
4. log.info("Starting tearDown thread groups");
5. if (mainGroups && !running) { // i.e. shutdown/stopped during main
6. // thread groups
7. running = shutdown && tearDownOnShutdown; // re-enable for
8. // tearDown if
9. // necessary
10. }
11. while (running && postIter.hasNext()) {// for each setup thread
12. // group
13. AbstractThreadGroup group = postIter.next();
14. groupCount++;
15. String groupName = group.getName();
16. log.info("Starting tearDown ThreadGroup: " + groupCount + " : " + groupName);
17. startThreadGroup(group, groupCount, postSearcher, testLevelElements, notifier);
18. if (serialized && postIter.hasNext()) {
19. log.info("Waiting for post thread group: " + groupName
20. + " to finish before starting next post group");
21. group.waitThreadsStopped();
22. }
23. }
24. waitThreadsStopped(); // wait for Post threads to stop
25. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
触发第三步中解析的 testListener 的 testEnded 方法:JavaSampler 会调用真正跑的 AbstractJavaSamplerClient 的 teardownTest 方法,可以打印该 JavaSamplerClient 测试总共花费的时间;
- ResultCollector 用来将测试结果写如文件生成;
- reportTestPlan 用来关闭文件。
1. notifyTestListenersOfEnd(testListeners);
2. JMeterContextService.endTest();
- 1.
- 2.
- 3.
startThreadGroup
启动线程组,run 方法中调用
1. private void startThreadGroup(AbstractThreadGroup group, int groupCount, SearchByClass<?> searcher,
2. List<?> testLevelElements, ListenerNotifier notifier) {
3. try {
4. int numThreads = group.getNumThreads();
5. JMeterContextService.addTotalThreads(numThreads);
6. boolean onErrorStopTest = group.getOnErrorStopTest();
7. boolean onErrorStopTestNow = group.getOnErrorStopTestNow();
8. boolean onErrorStopThread = group.getOnErrorStopThread();
9. boolean onErrorStartNextLoop = group.getOnErrorStartNextLoop();
10. String groupName = group.getName();
11. log.info("Starting " + numThreads + " threads for group " + groupName + ".");
12.
13. if (onErrorStopTest) {
14. log.info("Test will stop on error");
15. } else if (onErrorStopTestNow) {
16. log.info("Test will stop abruptly on error");
17. } else if (onErrorStopThread) {
18. log.info("Thread will stop on error");
19. } else if (onErrorStartNextLoop) {
20. log.info("Thread will start next loop on error");
21. } else {
22. log.info("Thread will continue on error");
23. }
24. ListedHashTree threadGroupTree = (ListedHashTree) searcher.getSubTree(group);
25. threadGroupTree.add(group, testLevelElements);
26.
27. groups.add(group);
28. group.start(groupCount, notifier, threadGroupTree, this);
29. } catch (JMeterStopTestException ex) { // NOSONAR Reported by log
30. JMeterUtils.reportErrorToUser("Error occurred starting thread group :" + group.getName()
31. + ", error message:" + ex.getMessage() + ", \r\nsee log file for more details", ex);
32. return; // no point continuing
33. }
34. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
waitThreadsStopped
等待线程停止,run 方法中调用
1. /**
2. * Wait for Group Threads to stop
3. */
4. private void waitThreadsStopped() {
5. // ConcurrentHashMap does not need synch. here
6. for (AbstractThreadGroup threadGroup : groups) {
7. threadGroup.waitThreadsStopped();
8. }
9. }
10.
11. /**
12. * Wait for all Group Threads to stop
13. */
14. @Override
15. public void waitThreadsStopped() {
16. if (delayedStartup) {
17. waitThreadStopped(threadStarter);
18. }
19. for (Thread t : allThreads.values()) {
20. waitThreadStopped(t);
21. }
22. }
23.
24. /**
25. * Wait for thread to stop
26. * @param thread Thread
27. */
28. private void waitThreadStopped(Thread thread) {
29. if (thread != null) {
30. while (thread.isAlive()) {
31. try {
32. thread.join(WAIT_TO_DIE);
33. } catch (InterruptedException e) {
34. Thread.currentThread().interrupt();
35. }
36. }
37. }
38. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
removeThreadGroups
移除线程组,在 run 方法里调用
1. private void removeThreadGroups(List<?> elements) {
2. Iterator<?> iter = elements.iterator();
3. while (iter.hasNext()) { // Can't use for loop here because we remove elements
4. Object item = iter.next();
5. if (item instanceof AbstractThreadGroup || !(item instanceof TestElement)) {
6. iter.remove();
7. }
8. }
9. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
runTest
runTest( ),调用该方法用来执行测试,启动一个线程并触发它的run()方法,若报异常则调用stopTest(),抛出 JMeterEngineException。
1. // 调用该方法用来执行测试,启动一个线程并触发它的run()方法,若报异常则调用stopTest(),抛出JMeterEngineException
2. @Override
3. public void runTest() throws JMeterEngineException {
4. if (host != null){
5. long now=System.currentTimeMillis();
6. System.out.println("Starting the test on host " + host + " @ "+new Date(now)+" ("+now+")"); // NOSONAR Intentional
7. }
8. try {
9. Thread runningThread = new Thread(this, "StandardJMeterEngine");
10. // 启动一个线程并触发它的run()方法
11. runningThread.start();
12. } catch (Exception err) {
13. stopTest();
14. throw new JMeterEngineException(err);
15. }
16. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
stopThread
根据 threadName 停止线程的执行:分两种情况立即停止和非立即停止,根据第二个参数的值决定
1. //根据threadName停止线程的执行:分两种情况立即停止和非立即停止,根据第二个参数的值决定
2. public static boolean stopThread(String threadName) {
3. return stopThread(threadName, false);
4. }
5.
6. public static boolean stopThreadNow(String threadName) {
7. return stopThread(threadName, true);
8. }
9.
10. private static boolean stopThread(String threadName, boolean now) {
11. if (engine == null) {
12. return false;// e.g. not yet started
13. }
14. boolean wasStopped = false;
15. // ConcurrentHashMap does not need synch. here
16. for (AbstractThreadGroup threadGroup : engine.groups) {
17. wasStopped = wasStopped || threadGroup.stopThread(threadName, now);
18. }
19. return wasStopped;
20. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
ThreadGroup.stopThread调用及具体实现代码如下:
1. /**
2. * Stop thread called threadName:
3. * <ol>
4. * <li>stop JMeter thread</li>
5. * <li>interrupt JMeter thread</li>
6. * <li>interrupt underlying thread</li>
7. * </ol>
8. * @param threadName String thread name
9. * @param now boolean for stop
10. * @return true if thread stopped
11. */
12. @Override
13. public boolean stopThread(String threadName, boolean now) {
14. for (Entry<JMeterThread, Thread> threadEntry : allThreads.entrySet()) {
15. JMeterThread jMeterThread = threadEntry.getKey();
16. if (jMeterThread.getThreadName().equals(threadName)) {
17. stopThread(jMeterThread, threadEntry.getValue(), now);
18. return true;
19. }
20. }
21. return false;
22. }
23.
24. /**
25. * Hard Stop JMeterThread thrd and interrupt JVM Thread if interrupt is true
26. * @param jmeterThread {@link JMeterThread}
27. * @param jvmThread {@link Thread}
28. * @param interrupt Interrupt thread or not
29. */
30. private void stopThread(JMeterThread jmeterThread, Thread jvmThread, boolean interrupt) {
31. jmeterThread.stop();
32. jmeterThread.interrupt(); // interrupt sampler if possible
33. if (interrupt && jvmThread != null) { // Bug 49734
34. jvmThread.interrupt(); // also interrupt JVM thread
35. }
36. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
stopTest
stopTest(boolean now)
测试,若 now 为 true 则停止动作立即执行;若为 false 则停止动作缓刑,它会等待当前正在执行的测试至少执行完一个 iteration。
1. // 停止测试,若now为true则停止动作立即执行;若为false则停止动作缓刑,它会等待当前正在执行的测试至少执行完一个iteration。
2. @Override
3. public synchronized void stopTest(boolean now) {
4. Thread stopThread = new Thread(new StopTest(now));
5. stopThread.start();
6. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
stopTest()
立即停止执行测试
1. /**
2. * Stop Test Now
3. */
4. @Override
5. public synchronized void stopTest() {
6. stopTest(true);
7. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
notifyTestListenersOfStart
测试开始通知监听
1. private void notifyTestListenersOfStart(SearchByClass<TestStateListener> testListeners) {
2. for (TestStateListener tl : testListeners.getSearchResults()) {
3. if (tl instanceof TestBean) {
4. TestBeanHelper.prepare((TestElement) tl);
5. }
6. if (host == null) {
7. tl.testStarted();
8. } else {
9. tl.testStarted(host);
10. }
11. }
12. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
介绍本方法需要了解下 TestStateListener 接口
1. package org.apache.jmeter.testelement;
2.
3. /**
4. * @since 2.8
5. */
6. public interface TestStateListener {
7.
8. /**
9. * <p>
10. * Called just before the start of the test from the main engine thread.
11. *
12. * This is before the test elements are cloned.
13. *
14. * Note that not all the test
15. * variables will have been set up at this point.
16. * </p>
17. *
18. * <p>
19. * <b>
20. * N.B. testStarted() and testEnded() are called from different threads.
21. * </b>
22. * </p>
23. * @see org.apache.jmeter.engine.StandardJMeterEngine#run()
24. *
25. */
26. void testStarted();
27.
28. /**
29. * <p>
30. * Called just before the start of the test from the main engine thread.
31. *
32. * This is before the test elements are cloned.
33. *
34. * Note that not all the test
35. * variables will have been set up at this point.
36. * </p>
37. *
38. * <p>
39. * <b>
40. * N.B. testStarted() and testEnded() are called from different threads.
41. * </b>
42. * </p>
43. * @see org.apache.jmeter.engine.StandardJMeterEngine#run()
44. * @param host name of host
45. */
46. void testStarted(String host);
47.
48. /**
49. * <p>
50. * Called once for all threads after the end of a test.
51. *
52. * This will use the same element instances as at the start of the test.
53. * </p>
54. *
55. * <p>
56. * <b>
57. * N.B. testStarted() and testEnded() are called from different threads.
58. * </b>
59. * </p>
60. * @see org.apache.jmeter.engine.StandardJMeterEngine#stopTest()
61. *
62. */
63. void testEnded();
64.
65. /**
66. * <p>
67. * Called once for all threads after the end of a test.
68. *
69. * This will use the same element instances as at the start of the test.
70. * </p>
71. *
72. * <p>
73. * <b>
74. * N.B. testStarted() and testEnded() are called from different threads.
75. * </b>
76. * </p>
77. * @see org.apache.jmeter.engine.StandardJMeterEngine#stopTest()
78. * @param host name of host
79. *
80. */
81.
82. void testEnded(String host);
83.
84. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- testStarted:在测试开始之前调用
- testEnded:在所有线程测试结束时调用一次
notifyTestListenersOfEnd
测试结束通知监听
1. private void notifyTestListenersOfEnd(SearchByClass<TestStateListener> testListeners) {
2. log.info("Notifying test listeners of end of test");
3. for (TestStateListener tl : testListeners.getSearchResults()) {
4. try {
5. if (host == null) {
6. tl.testEnded();
7. } else {
8. tl.testEnded(host);
9. }
10. } catch (Exception e) {
11. log.warn("Error encountered during shutdown of "+tl.toString(),e);
12. }
13. }
14. if (host != null) {
15. log.info("Test has ended on host {} ", host);
16. long now=System.currentTimeMillis();
17. System.out.println("Finished the test on host " + host + " @ "+new Date(now)+" ("+now+")" // NOSONAR Intentional
18. +(EXIT_AFTER_TEST ? " - exit requested." : ""));
19. if (EXIT_AFTER_TEST){
20. exit();
21. }
22. }
23. active=false;
24. }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
单机执行
1. // 加载jmx文件
2. FileServer.getFileServer().setBaseForScript(jmxFile);
3. // 设置jmx脚本文件的工作目录
4. HashTree jmxTree = SaveService.loadTree(jmxFile);
5. // 去掉没用的节点元素,替换掉可以替换的控制器
6. JMeter.convertSubTree(jmxTree);
7.
8. // 初始化默认的压测引擎
9. JMeterEngine engine = new StandardJMeterEngine();
10. engine.configure(jmxTree);
11. engine.runTest();
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
分布式执行
1. // 分布式执行脚本,StringTokenizer是为了初始化hosts参数
2. // DistributedRunner本质上还是StandardJMeterEngine来执行的压测,使用的是rmi的协议实现的分布式压测。
3. java.util.StringTokenizer st = new java.util.StringTokenizer(remoteHostsString, ",");//$NON-NLS-1$
4. List<String> hosts = new LinkedList<>();
5. while (st.hasMoreElements()) {
6. hosts.add((String) st.nextElement());
7. }
8.
9. DistributedRunner distributedRunner=new DistributedRunner(this.remoteProps);
10. distributedRunner.setStdout(System.out); // NOSONAR
11. distributedRunner.setStdErr(System.err); // NOSONAR
12. distributedRunner.init(hosts, clonedTree);
13. engines.addAll(distributedRunner.getEngines());
14. distributedRunner.start();
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
StringTokenizer 是为了初始化hosts参数使用的。 DistributedRunner 本质上还是 StandardJMeterEngine 来执行的压测,使用的是 RMI 的协议实现的分布式压测。
版权声明
本文为[高楼(Zee)]所创,转载请带上原文链接,感谢
https://blog.51cto.com/u_15181572/4285608
边栏推荐
- Better Scala I / O: better files
- Implementation of prefork and affinity in go web server
- Peak duel - Framework performance comparison
- Scala native will be released soon
- Principe du crochet d'arrêt
- Plate - forme d'efficacité panoramique agent de poisson - dent de porc - mise à niveau des composants d'aide
- Elk7.15.1 installation et déploiement
- 5 raisons et solutions de la lenteur du fonctionnement de l'application
- Using Visual Studio code to develop go program
- Go scheduler tracking
猜你喜欢
-
Go stack trace
-
Go channel details
-
Go generic proposal
-
Implementing futures and promises using golang
-
Amdal's law
-
Who is the fastest go web framework
-
[transfer] golang automatically generates version information
-
Is iris really the fastest golang routing framework?
-
SAP Fiori里的List是如何做到懒加载Lazy load的
-
SAP UI5和CRM WebUI的View和Controller是如何绑定的
随机推荐
- 如何将Twitter的内容导入到SAP CRM和C4C
- How to find the occurrence frequency of top 100 for 100 machines?
- 2018年系统架构设计师上午真题及答案解析
- How to get the ID of goroutine?
- Uncover the secrets of vert. X threading model
- spymemcached vs. xmemcached vs. Folsom
- Golang serialization framework duel - why is andyleap / gencode so fast?
- [transfer] summary of structural evolution of major Internet companies
- 2018年系統架構設計師上午真題及答案解析
- Golang通脉之方法
- 测试流程
- 数据库批量数据插入
- Analyse des vrais problèmes et des réponses des concepteurs d'architecture de système en 2018
- Comment importer du contenu Twitter dans SAP CRM et c4c
- Comment la vue et le Contrôleur de SAP ui5 et CRM webui sont liés
- Comment les listes dans SAP Fiori sont - elles paresseuses à charger lazy?
- 关于晋升的5个建议
- 需求的仙界
- Golang通脉之方法
- ShutdownHook原理
- Web framework performance benchmark (round 12)
- Description of asynchronous programming model
- Ignite vs Hazelcast
- Performance of 1 million threads
- Scala async Library
- Scala magic function
- Item based collaborative filtering recommendation system for Douban movies
- ShutdownHook原理
- Golang通脈之方法
- Principe du crochet d'arrêt
- Méthode de communication du pouls de golang
- Fairyland of Demand
- 5 Recommandations concernant les promotions
- Insertion de données par lots dans la base de données
- idea提交时忽略.class、.iml文件和文件夹或目录的方法
- Processus d'essai
- User based collaborative filtering recommendation system for Douban movies
- Use spark mllib to recommend movies to Douban users
- Web framework performance benchmarking
- A pit in spymemcached