public void startTest(PutGetHelper putGetHelper, int maxParallelPutCount, int parallelGetCount, int totalPutCount,
      int maxGetCountPerBlob, int burstCountGet, int maxFailuresPerPutBatchToStopPuts,
      int maxFailuresPerGetBatchToStopGets, boolean deleteAndValidate, long sleepTimeBetweenBatchPutsInMs,
      long sleepTimeBetweenBatchGetsInMs, long measurementIntervalInSecs) throws InterruptedException {
    AtomicInteger currentPutCount = new AtomicInteger(0);
    AtomicInteger getCompletedCount = new AtomicInteger(0);
    // Creating shared queue for put Thread and get Thread
    CopyOnWriteArrayList<BlobAccessInfo> generatedBlobAccessInfos = new CopyOnWriteArrayList<BlobAccessInfo>();
    BlockingQueue<String> deletedBlobIds = new LinkedBlockingQueue<>();
    final ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();

    // Creating PutThread
    Thread putThread = new Thread(
        new PutThread(putGetHelper, generatedBlobAccessInfos, totalPutCount, currentPutCount, maxParallelPutCount,
            maxFailuresPerPutBatchToStopPuts, sleepTimeBetweenBatchPutsInMs, threadLocalRandom,
            measurementIntervalInSecs));

    // Creating Get thread
    Thread getThread = new Thread(
        new GetThread(putGetHelper, generatedBlobAccessInfos, maxGetCountPerBlob, currentPutCount, getCompletedCount,
            burstCountGet, parallelGetCount, maxFailuresPerGetBatchToStopGets, sleepTimeBetweenBatchGetsInMs,
            deleteAndValidate, threadLocalRandom, deletedBlobIds, measurementIntervalInSecs));

    Thread deleteThread = null;
    if (deleteAndValidate) {
      logger.trace("Initiating Delete thread ");
      DeleteThread deleteBlobThread =
          new DeleteThread(putGetHelper, totalPutCount, deletedBlobIds, measurementIntervalInSecs);
      deleteThread = new Thread(deleteBlobThread);
      deleteThread.start();
    }

    putThread.start();
    getThread.start();

    putThread.join();
    getThread.join();

    if (deleteThread != null) {
      logger.trace("Starting Delete thread ");
      deleteThread.join();
    }

    logger.trace("Invoking shutdown after completing the test suite ");
    // shutting down the PutGetHelper class to release any resources held up
    putGetHelper.shutdown();
  }
Initializes and starts the concurrent test tool.
@param putGetHelper the {@link PutGetHelper} to be used for PUTs and GETs
@param maxParallelPutCount maximum number of parallel puts per phase
@param parallelGetCount the number of parallel Gets per phase
@param totalPutCount total number of blobs to be uploaded
@param maxGetCountPerBlob total number of times a particular blob can be fetched before its deleted
@param burstCountGet Burst count for GETs. Each GET consumer thread will fetch a blob these many no of
                        times simultaneously
@param maxFailuresPerPutBatchToStopPuts Maximum allowable failures per Put batch in order to continue with PUTs
@param maxFailuresPerGetBatchToStopGets Maximum allowable failures per Get batch in order to continue with GETs
@param deleteAndValidate Deletes the blobs once GETs have reached a threshold on every blob
@param sleepTimeBetweenBatchPutsInMs Time to sleep in ms between batch Puts per Producer thread
@param sleepTimeBetweenBatchGetsInMs Time to sleep in ms between batch Gets per Consumer thread
@param measurementIntervalInSecs The interval in seconds to report performance result
@throws InterruptedException
ambry-tools/src/main/java/com/github/ambry/tools/admin/ConcurrencyTestTool.java