我正在写java的性能测试。 主要思想是创建方法loadTest(String url,int threadNumber,int requestNumber),它将返回成功请求的总时间和成功请求的数量。 但我仍然坚持返回数据。
现在如果我运行此测试 MyRunnable.getTotalTime()和MyRunnable.getCountSuccessRequest()返回0; (控制台中的第一个字符串 并在控制台的输出结束时更正值。 我希望他们回来
我如何才能返回正确的值?
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestMain {
public static void main(String [] args) {
System.out.println("Start test.");
TestMain test = new TestMain();
test.loadTest("http://www.google.com/search?q=java", 10, 50); // will execute 50 get request in 10 threads.
}
public void loadTest(String site, int threadNumber, int requestNumber) {
ExecutorService executor = Executors.newFixedThreadPool(threadNumber);
for ( int i = 0; i < requestNumber; i++ ) {
Runnable worker = new MyRunnable(site);
executor.execute(worker);
}
//System.out.println("Total time " + MyRunnable.getTotalTime() + " total success request = " + MyRunnable.getCountSuccessRequest() );//still not work
}
}
班级
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class MyRunnable implements Runnable {
private static final String USER_AGENT = "Chrome";
private static int count = 1;
private static int countSuccessRequest = 0;
private static long totalTime ;
private final String url;
public MyRunnable(String url) {
this.url = url;
}
//<________edit__________>
SyncronizedCounter sc = new SyncronizedCounter();
//<________edit__________>
public static long getTotalTime() {
return totalTime;
}
public static int getCountSuccessRequest() {
return countSuccessRequest;
}
@Override
public void run() {
try {
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", USER_AGENT);
long startTime = System.currentTimeMillis();
int responseCode = con.getResponseCode();
long elapseTime = System.currentTimeMillis() - startTime;
totalTime += elapseTime;
count++;
if (responseCode == 200 ) {
countSuccessRequest ++;
}
//<________edit__________>
sc.incrementTime(elapseTime);
//<________edit__________>
System.out.println("\nSending 'GET' request to URL : " + url );
System.out.println("Response Code : " + responseCode);
System.out.println("Response time : " + elapseTime + " milliseconds\n");
System.out.println("----Total time for all request = " + totalTime + " mileseconds");
System.out.println("----Total count of request = " + count);
System.out.println("----Count of success request = " + countSuccessRequest);
in.close();
} catch (Exception e) {
}
}
//<________edit__________>
public class SyncronizedCounter{
private long totalTime1 = 0;
public synchronized void incrementTime( long time){
totalTime1 += time;
}
public synchronized long getTime() {
return totalTime1;
}
}
//<________edit__________>
}
我的附加编辑标记为&lt; ______编辑________ &gt;。我在方法run()中添加了包装类和实例。我怎样才能获得TestMain.class中的最后一个值
答案 0 :(得分:0)
创建一个胶囊对象Stats
(它必须是非原始的)并给它方法
public synchronized void addTotalTime(long elapsed)
public synchronized void addSuccessCount(long elapsed)
public synchronized void addTotalCount(long elapsed)
这确保了不会同时执行+=
次操作,因此没有竞争条件会将不确定性置于将存储到变量中的值中。
有关技术细节,请参阅here。
代码存根看起来像这样
private class Stats {
private int success, total;
private long time;
public synchronized void addTotalTime(long elapsed) { time += elapsed; }
public synchronized void addSuccesCount(int c) { sucess += c; }
public synchronized void addTotalCount(int c) { total += c; }
public long getTotalTime() { return time; }
public int getSuccessCount() { return success; }
public int getTotalCount() { return total; }
}
Stats s = new Stats();
// in worker:
s.add...(...)
// at end:
System.out.println(s.get...());
答案 1 :(得分:0)
我建议使用executor.submit(yourRunnable)
,并且您的主题将返回他们作为Future<Integer>
工作的时间。之后只需总结所有退回的期货。
答案 2 :(得分:0)
假设你想要一个运行计数,而不仅仅是最后的总数,我会使用ReentrantLock来处理更新,并使用Callables和Futures而不是Runnable来处理http请求。
一般情况下,最好避免显式同步,并尽可能依赖java.util.concurrent。
以下是Java 6/7和Java 8中的示例解决方案。
Java 6/7
public class TestMainJdk7 {
public static void main(final String... args) throws Exception {
final TestRun testRun = new TestRun("http://www.google.com/search?q=java", "Chrome", 5, 5, 100000L);
final TestResults testResults = testRun.execute();
// Uncomment and add Apache commons-math to report quantiles, mean, min, max, standard deviation
// for (int quantile = 5; quantile <= 100; quantile += 5) {
// System.out.println(quantile + ": " + testResults.rawDescriptiveStatistics.getPercentile(quantile));
// }
// System.out.println("mean: " + testResults.rawDescriptiveStatistics.getMean());
// System.out.println("min: " + testResults.rawDescriptiveStatistics.getMin());
// System.out.println("max: " + testResults.rawDescriptiveStatistics.getMax());
// System.out.println("standard deviation: " + testResults.rawDescriptiveStatistics.getStandardDeviation());
}
public static class TestResults {
private final double[] rawDurations;
public final TestRun testRun;
public final List<TimedHttpRequestResult> timedHttpRequestResults;
// Uncomment and add Apache commons-math to report quantiles, mean, min, max, standard deviation
// public final org.apache.commons.math.stat.descriptive.DescriptiveStatistics rawDescriptiveStatistics;
public TestResults(final TestRun testRun, final List<TimedHttpRequestResult> timedHttpRequestResults) {
this.testRun = testRun;
this.timedHttpRequestResults = timedHttpRequestResults;
final List<Long> successfulDurations = new ArrayList<Long>();
for (final TimedHttpRequestResult timedHttpRequestResult : timedHttpRequestResults) {
if (timedHttpRequestResult.isSuccess()) {
successfulDurations.add(timedHttpRequestResult.duration);
}
}
this.rawDurations = new double[successfulDurations.size()];
for (int i = 0; i < successfulDurations.size(); i++) {
this.rawDurations[i] = successfulDurations.get(i);
}
// Uncomment and add Apache commons-math to report quantiles, mean, min, max, standard deviation
// this.rawDescriptiveStatistics = new org.apache.commons.math.stat.descriptive.DescriptiveStatistics(
// this.rawDurations);
}
}
public static class TestRun {
public final String urlString;
public final String userAgentString;
public final int threadNumber;
public final int requestNumber;
public final long timeoutInMillis;
private long totalDurationSoFar;
private int totalRunSoFar;
private int totalSuccessfulSoFar;
private final ReentrantLock lock = new ReentrantLock();
public TestRun(final String urlString, final String userAgentString, final int threadNumber,
final int requestNumber, final long timeoutInMillis) {
this.urlString = urlString;
this.threadNumber = threadNumber;
this.requestNumber = requestNumber;
this.userAgentString = userAgentString;
this.timeoutInMillis = timeoutInMillis;
}
public TestRunStatus updateCounts(final long duration, final int responseCode) {
this.lock.lock();
try {
this.totalDurationSoFar = this.totalDurationSoFar + duration;
this.totalRunSoFar++;
if (responseCode == HttpURLConnection.HTTP_OK) {
this.totalSuccessfulSoFar++;
}
return this.currentStatus();
} finally {
this.lock.unlock();
}
}
public TestRunStatus currentStatus() {
return new TestRunStatus(this.totalDurationSoFar, this.totalRunSoFar, this.totalSuccessfulSoFar);
}
public TestResults execute() throws InterruptedException {
final ExecutorService executor = Executors.newFixedThreadPool(this.threadNumber);
final Map<TimedHttpRequest, Future<TimedHttpRequestResult>> timedHttpRequestFuturesByRequest = new HashMap<TimedHttpRequest, Future<TimedHttpRequestResult>>();
for (int i = 0; i < this.requestNumber; i++) {
final TimedHttpRequest timedHttpRequest = new TimedHttpRequest(this);
timedHttpRequestFuturesByRequest.put(timedHttpRequest, executor.submit(timedHttpRequest));
}
final List<TimedHttpRequestResult> timedHttpRequestResults = new ArrayList<TimedHttpRequestResult>();
for (final Map.Entry<TimedHttpRequest, Future<TimedHttpRequestResult>> timedHttpRequestFuture : timedHttpRequestFuturesByRequest.entrySet()) {
final TimedHttpRequest timedHttpRequest = timedHttpRequestFuture.getKey();
try {
timedHttpRequestResults.add(timedHttpRequestFuture.getValue()
.get(this.timeoutInMillis, TimeUnit.MILLISECONDS));
} catch (final Exception e) {
timedHttpRequestResults.add(new TimedHttpRequestResult(timedHttpRequest, e,
this.updateCounts(0, -1)));
}
}
executor.shutdown();
return new TestResults(this, timedHttpRequestResults);
}
}
public static class TestRunStatus {
public final long totalDurationSoFar;
public final int totalRunSoFar;
public final int totalSuccessfulSoFar;
TestRunStatus(final long totalDurationSoFar, final int totalRunSoFar, final int totalSuccessfulSoFar) {
this.totalDurationSoFar = totalDurationSoFar;
this.totalRunSoFar = totalRunSoFar;
this.totalSuccessfulSoFar = totalSuccessfulSoFar;
}
}
public static class TimedHttpRequestResult {
//@formatter:off
public static final String TO_STRING_FORMAT = "\nSending 'GET' request to URL : %s"
+ "\nResponse Code : %s"
+ "\nResponse time: %s"
+ "\n---- Total time for all request = %s milliseconds"
+ "\n---- Total count of request = %s"
+ "\n---- Count of success request = %s";
//@formatter:on
public final TimedHttpRequest timedHttpRequest;
public final long duration;
public final int responseCode;
public final Exception exception;
public final TestRunStatus testRunStatus;
public TimedHttpRequestResult(final TimedHttpRequest timedHttpRequest, final long duration,
final int responseCode, final TestRunStatus testRunStatus) {
this.timedHttpRequest = timedHttpRequest;
this.duration = duration;
this.responseCode = responseCode;
this.testRunStatus = testRunStatus;
this.exception = null;
}
public TimedHttpRequestResult(final TimedHttpRequest timedHttpRequest, final Exception exception,
final TestRunStatus testRunStatus) {
this.timedHttpRequest = timedHttpRequest;
this.duration = -1L;
this.responseCode = -1;
this.testRunStatus = testRunStatus;
this.exception = exception;
}
boolean isSuccess() {
return this.responseCode == HttpURLConnection.HTTP_OK;
}
@Override
public String toString() {
return String.format(TO_STRING_FORMAT, this.timedHttpRequest.testRun.urlString, this.responseCode,
this.duration, this.testRunStatus.totalDurationSoFar, this.testRunStatus.totalRunSoFar,
this.testRunStatus.totalSuccessfulSoFar);
}
}
public static class TimedHttpRequest implements Callable<TimedHttpRequestResult> {
public final TestRun testRun;
public TimedHttpRequest(final TestRun testRun) {
this.testRun = testRun;
}
@Override
public TimedHttpRequestResult call() throws Exception {
final URL url = new URL(this.testRun.urlString);
final HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setRequestProperty("User-Agent", this.testRun.userAgentString);
final long startTime = System.nanoTime();
final int responseCode = httpURLConnection.getResponseCode();
final long endTime = System.nanoTime();
httpURLConnection.disconnect();
final long duration = TimeUnit.NANOSECONDS.toMillis(endTime - startTime);
final TimedHttpRequestResult timedHttpRequestResult = new TimedHttpRequestResult(this, duration,
responseCode, this.testRun.updateCounts(duration, responseCode));
System.out.println(timedHttpRequestResult);
return timedHttpRequestResult;
}
}
}
Java 8
public class TestMainJdk8 {
public static void main(final String... args) throws Exception {
final TestRun testRun = new TestMainJdk8.TestRun("http://www.google.com/search?q=java", "Chrome", 5, 5,
100000L);
final TestResults testResults = testRun.execute();
// Uncomment and add Apache commons-math to report quantiles, mean, min, max, standard deviation
// for (int quantile = 5; quantile <= 100; quantile += 5) {
// System.out.println(quantile + ": " + testResults.rawDescriptiveStatistics.getPercentile(quantile));
// }
// System.out.println("mean: " + testResults.rawDescriptiveStatistics.getMean());
// System.out.println("min: " + testResults.rawDescriptiveStatistics.getMin());
// System.out.println("max: " + testResults.rawDescriptiveStatistics.getMax());
// System.out.println("standard deviation: " + testResults.rawDescriptiveStatistics.getStandardDeviation());
}
public static class TestResults {
private final double[] rawDurations;
public final TestRun testRun;
public final List<TimedHttpRequestResult> timedHttpRequestResults;
// Uncomment to report quantiles, mean, min, max, standard deviation
// public final org.apache.commons.math.stat.descriptive.DescriptiveStatistics rawDescriptiveStatistics;
public TestResults(final TestRun testRun, final List<TimedHttpRequestResult> timedHttpRequestResults) {
this.testRun = testRun;
this.timedHttpRequestResults = timedHttpRequestResults;
this.rawDurations = timedHttpRequestResults.stream()
.filter(TimedHttpRequestResult::isSuccess)
.mapToDouble(timedHttpRequestResult -> timedHttpRequestResult.duration)
.toArray();
// Uncomment and add Apache commons-math to report quantiles, mean, min, max, standard deviation
// this.rawDescriptiveStatistics = new org.apache.commons.math.stat.descriptive.DescriptiveStatistics(
// this.rawDurations);
}
}
public static class TestRun {
public final String urlString;
public final String userAgentString;
public final int threadNumber;
public final int requestNumber;
public final long timeoutInMillis;
private long totalDurationSoFar;
private int totalRunSoFar;
private int totalSuccessfulSoFar;
private final ReentrantLock lock = new ReentrantLock();
public TestRun(final String urlString, final String userAgentString, final int threadNumber,
final int requestNumber, final long timeoutInMillis) {
this.urlString = urlString;
this.threadNumber = threadNumber;
this.requestNumber = requestNumber;
this.userAgentString = userAgentString;
this.timeoutInMillis = timeoutInMillis;
}
public TestRunStatus updateCounts(final long duration, final int responseCode) {
this.lock.lock();
try {
this.totalDurationSoFar = this.totalDurationSoFar + duration;
this.totalRunSoFar++;
if (responseCode == HttpURLConnection.HTTP_OK) {
this.totalSuccessfulSoFar++;
}
return this.currentStatus();
} finally {
this.lock.unlock();
}
}
public TestRunStatus currentStatus() {
return new TestRunStatus(this.totalDurationSoFar, this.totalRunSoFar, this.totalSuccessfulSoFar);
}
public TestResults execute() throws InterruptedException {
final ExecutorService executor = Executors.newFixedThreadPool(this.threadNumber);
final Map<TimedHttpRequest, Future<TimedHttpRequestResult>> timedHttpRequestFuturesByRequest = IntStream.range(
1, this.requestNumber)
.mapToObj(index -> new TimedHttpRequest(this))
.collect(Collectors.toMap(Function.identity(), timedHttpRequest -> executor.submit(timedHttpRequest)));
final List<TimedHttpRequestResult> timedHttpRequestResults = timedHttpRequestFuturesByRequest.entrySet()
.stream()
.map(entry -> {
final TimedHttpRequest timedHttpRequest = entry.getKey();
try {
return entry.getValue()
.get(this.timeoutInMillis, TimeUnit.MILLISECONDS);
} catch (final Exception e) {
return new TimedHttpRequestResult(timedHttpRequest, e, this.updateCounts(0, -1));
}
})
.collect(Collectors.toList());
executor.shutdown();
return new TestResults(this, timedHttpRequestResults);
}
}
public static class TestRunStatus {
public final long totalDurationSoFar;
public final int totalRunSoFar;
public final int totalSuccessfulSoFar;
TestRunStatus(final long totalDurationSoFar, final int totalRunSoFar, final int totalSuccessfulSoFar) {
this.totalDurationSoFar = totalDurationSoFar;
this.totalRunSoFar = totalRunSoFar;
this.totalSuccessfulSoFar = totalSuccessfulSoFar;
}
}
public static class TimedHttpRequestResult {
//@formatter:off
public static final String TO_STRING_FORMAT = "\nSending 'GET' request to URL : %s"
+ "\nResponse Code : %s"
+ "\nResponse time: %s"
+ "\n---- Total time for all request = %s milliseconds"
+ "\n---- Total count of request = %s"
+ "\n---- Count of success request = %s";
//@formatter:on
public final TimedHttpRequest timedHttpRequest;
public final long duration;
public final int responseCode;
public final Exception exception;
public final TestRunStatus testRunStatus;
public TimedHttpRequestResult(final TimedHttpRequest timedHttpRequest, final long duration,
final int responseCode, final TestRunStatus testRunStatus) {
this.timedHttpRequest = timedHttpRequest;
this.duration = duration;
this.responseCode = responseCode;
this.testRunStatus = testRunStatus;
this.exception = null;
}
public TimedHttpRequestResult(final TimedHttpRequest timedHttpRequest, final Exception exception,
final TestRunStatus testRunStatus) {
this.timedHttpRequest = timedHttpRequest;
this.duration = -1L;
this.responseCode = -1;
this.testRunStatus = testRunStatus;
this.exception = exception;
}
boolean isSuccess() {
return this.responseCode == HttpURLConnection.HTTP_OK;
}
@Override
public String toString() {
return String.format(TO_STRING_FORMAT, this.timedHttpRequest.testRun.urlString, this.responseCode,
this.duration, this.testRunStatus.totalDurationSoFar, this.testRunStatus.totalRunSoFar,
this.testRunStatus.totalSuccessfulSoFar);
}
}
public static class TimedHttpRequest implements Callable<TimedHttpRequestResult> {
public final TestRun testRun;
public TimedHttpRequest(final TestRun testRun) {
this.testRun = testRun;
}
@Override
public TimedHttpRequestResult call() throws Exception {
final URL url = new URL(this.testRun.urlString);
final HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setRequestProperty("User-Agent", this.testRun.userAgentString);
final long startTime = System.nanoTime();
final int responseCode = httpURLConnection.getResponseCode();
final long endTime = System.nanoTime();
httpURLConnection.disconnect();
final long duration = TimeUnit.NANOSECONDS.toMillis(endTime - startTime);
final TimedHttpRequestResult timedHttpRequestResult = new TimedHttpRequestResult(this, duration,
responseCode, this.testRun.updateCounts(duration, responseCode));
System.out.println(timedHttpRequestResult);
return timedHttpRequestResult;
}
}
}