2014-07-17 121 views
0

我正在java上编写性能测试。 主要想法创建方法loadTest(String url,int threadNumber,int requestNumber)将返回成功请求的总时间和成功请求的数量。 但我坚持返回数据。java线程全局变量的同步

所以现在如果我运行这个测试 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__________> 
} 

我的其他编辑标记为< ______edit________>。我在run()方法中添加了包装类和实例。我怎么能在TestMain.class

回答

0

创建一个胶囊对象Stats得到最后的值(它必须是非原语),并给它的方法

public synchronized void addTotalTime(long elapsed) 
public synchronized void addSuccessCount(long elapsed) 
public synchronized void addTotalCount(long elapsed) 

这将确保没有+=上同时进行如此不竞争条件会使不确定性存储到变量中。 有关技术细节,请参阅here


A码存根看起来像这样

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...()); 
+0

这是主要的问题为了我。它应该如何工作? – user3737721

+0

你卡在哪里?如何创建一个类?如何编写这些方法?如何访问这些方法? – AlexR

+0

这是我的主要问题。它应该如何工作?创建新类SyncronizedCounter {private long totalTimeMy = 0; public syncronized void incrementTime(long time){totalTimeMy + = time;} public syncronized void getTime(){return totalTimeMy;}}。比我应该在MyRunnable中创建instantce并在方法运行中更改它。但我如何获得最后的价值。我不知道如何在TestMain.class中做到这一点。 – user3737721

0

我会建议使用executor.submit(yourRunnable)和你的线程返回他们工作作为Future<Integer>的时间。之后只需总结所有退回的期货。

+0

但是,我只想获得成功请求的时间。不是全部。谢谢。 – user3737721

0

假设你想要一个运行计数,而不仅仅是最后的总数,我会使用ReentrantLock来处理更新,并使用Callables和Futures而不是Runnable来处理http请求。

通常,最好避免显式同步,并尽可能依赖java.util.concurrent。

下面是在Java 6/7和Java示例解决方案8.

爪哇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; 
     } 

    } 
} 

爪哇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; 
     } 
    } 
} 
+0

但我最终只需要总计。)我会检查你的代码谢​​谢。 – user3737721

+0

如果是这种情况,请在总持续时间内使用AtomicInteger.increment获取请求计数和成功计数以及AtomicLong.getAndAdd(duration)。 – Jeff

+0

需要RentrantLock以允许在单个事务中更改所有值。 – Jeff