public void testConcurrentJoinsAndLeaves() throws Exception {
    for (int i = 0; i < threads.length; i++) {
      threads[i] = new MyThread(i, barrier);
      threads[i].start();
    }

    barrier.await(); // causes all threads to call Channel.connect()

    // coordinator attempts to get complete view within 50 (5*10) seconds
    int min = NUM, max = 0;
    for (int i = 0; i < 20; i++) {
      for (MyThread thread : threads) {
        JChannel ch = thread.getChannel();
        View view = ch.getView();
        if (view != null) {
          int size = view.size();
          min = Math.min(size, NUM);
          max = Math.max(size, max);
        }
      }

      if (min >= NUM && max >= NUM) break;
      System.out.println("min=" + min + ", max=" + max);
      Util.sleep(2000);
    }

    System.out.println("reached " + NUM + " members: min=" + min + ", max=" + max);
    assert min >= NUM && max >= NUM : "min=" + min + ", max=" + max + ", expected: " + NUM;

    System.out.println("Starting the disconnect phase");

    for (int i = 0; i < threads.length; i++) {
      MyThread thread = threads[i];
      System.out.print("disconnecting " + thread.getName());
      thread.disconnect();
      System.out.println(" OK");
    }
  }