Hacker News new | ask | show | jobs
by edgeztv 6141 days ago
My solution for multithreaded testing in Java. Been using this code for a couple of years. Can easily be generalized for any asynchronous task. The main concept is using a shared barrier construct.

  /**
   * Executes the task the given number of times in the given number of threads
   * @return All the unchecked exceptions thrown by the task during execution, or
   * an empty collection; never null.
   */
  public Collection<Throwable> run(Runnable task, int nThreads, final int iterationsPerThread) throws BrokenBarrierException, InterruptedException {
    // each thread will await upon the start barrier, then run the task, then await at the finish barrier (where the main thread will be waiting)
    final CyclicBarrier startBarrier = new CyclicBarrier(nThreads);
    final CyclicBarrier finishBarrier = new CyclicBarrier(nThreads + 1);  // +1 for the main thread
    // exceptions raised by threads will be logged and returned
    final Collection<Throwable> exceptions = new ConcurrentLinkedQueue<Throwable>();

    for (int i = 0; i < nThreads; i++) {
      new Thread("Thread " + i) {
        public void run() {
          awaitOnBarrier(startBarrier, 5);
          try {
            for (int j = 0; j < iterationsPerThread; j++) {
              task.run();
            }
          }
          catch (Throwable e) {
            e.printStackTrace();
            exceptions.add(e);
          }
          finally {
            awaitOnBarrier(finishBarrier, 60);
          }
        }
      }.start();
    }
    finishBarrier.await();
    return exceptions;
  }


  /** Calls barrier.await and supresses all its checked exceptions */
  private void awaitOnBarrier(CyclicBarrier barrier, int timeoutSeconds) {
    try {
      barrier.await(timeoutSeconds, TimeUnit.SECONDS);
    }
    catch (InterruptedException e) {
      e.printStackTrace();
      throw new RuntimeException(e);
    }
    catch (BrokenBarrierException e) {
      e.printStackTrace();
      throw new RuntimeException(e);
    }
    catch (TimeoutException e) {
      e.printStackTrace();
      throw new RuntimeException(e);
    }
  }