Example usage for java.util.concurrent Semaphore release

List of usage examples for java.util.concurrent Semaphore release

Introduction

In this page you can find the example usage for java.util.concurrent Semaphore release.

Prototype

public void release() 

Source Link

Document

Releases a permit, returning it to the semaphore.

Usage

From source file:org.apache.hadoop.hdfs.TestBlockReaderFactory.java

/**
 * When an InterruptedException is sent to a thread calling
 * FileChannel#read, the FileChannel is immediately closed and the
 * thread gets an exception.  This effectively means that we might have
 * someone asynchronously calling close() on the file descriptors we use
 * in BlockReaderLocal.  So when unreferencing a ShortCircuitReplica in
 * ShortCircuitCache#unref, we should check if the FileChannel objects
 * are still open.  If not, we should purge the replica to avoid giving
 * it out to any future readers.//  w w w  .  j a v  a  2s.  c om
 *
 * This is a regression test for HDFS-6227: Short circuit read failed
 * due to ClosedChannelException.
 *
 * Note that you may still get ClosedChannelException errors if two threads
 * are reading from the same replica and an InterruptedException is delivered
 * to one of them.
 */
@Test(timeout = 120000)
public void testPurgingClosedReplicas() throws Exception {
    BlockReaderTestUtil.enableBlockReaderFactoryTracing();
    final AtomicInteger replicasCreated = new AtomicInteger(0);
    final AtomicBoolean testFailed = new AtomicBoolean(false);
    DFSInputStream.tcpReadsDisabledForTesting = true;
    BlockReaderFactory.createShortCircuitReplicaInfoCallback = new ShortCircuitCache.ShortCircuitReplicaCreator() {
        @Override
        public ShortCircuitReplicaInfo createShortCircuitReplicaInfo() {
            replicasCreated.incrementAndGet();
            return null;
        }
    };
    TemporarySocketDirectory sockDir = new TemporarySocketDirectory();
    Configuration conf = createShortCircuitConf("testPurgingClosedReplicas", sockDir);
    final MiniDFSCluster cluster = new MiniDFSCluster.Builder(conf).numDataNodes(1).build();
    cluster.waitActive();
    final DistributedFileSystem dfs = cluster.getFileSystem();
    final String TEST_FILE = "/test_file";
    final int TEST_FILE_LEN = 4095;
    final int SEED = 0xFADE0;
    final DistributedFileSystem fs = (DistributedFileSystem) FileSystem.get(cluster.getURI(0), conf);
    DFSTestUtil.createFile(fs, new Path(TEST_FILE), TEST_FILE_LEN, (short) 1, SEED);
    final Semaphore sem = new Semaphore(0);
    final List<LocatedBlock> locatedBlocks = cluster.getNameNode().getRpcServer()
            .getBlockLocations(TEST_FILE, 0, TEST_FILE_LEN).getLocatedBlocks();
    final LocatedBlock lblock = locatedBlocks.get(0); // first block
    final byte[] buf = new byte[TEST_FILE_LEN];
    Runnable readerRunnable = new Runnable() {
        @Override
        public void run() {
            try {
                while (true) {
                    BlockReader blockReader = null;
                    try {
                        blockReader = BlockReaderTestUtil.getBlockReader(cluster, lblock, 0, TEST_FILE_LEN);
                        sem.release();
                        try {
                            blockReader.readAll(buf, 0, TEST_FILE_LEN);
                        } finally {
                            sem.acquireUninterruptibly();
                        }
                    } catch (ClosedByInterruptException e) {
                        LOG.info("got the expected ClosedByInterruptException", e);
                        sem.release();
                        break;
                    } finally {
                        if (blockReader != null)
                            blockReader.close();
                    }
                    LOG.info("read another " + TEST_FILE_LEN + " bytes.");
                }
            } catch (Throwable t) {
                LOG.error("getBlockReader failure", t);
                testFailed.set(true);
                sem.release();
            }
        }
    };
    Thread thread = new Thread(readerRunnable);
    thread.start();
    // While the thread is reading, send it interrupts.
    // These should trigger a ClosedChannelException.
    while (thread.isAlive()) {
        sem.acquireUninterruptibly();
        thread.interrupt();
        sem.release();
    }
    Assert.assertFalse(testFailed.get());
    // We should be able to read from the file without
    // getting a ClosedChannelException.
    BlockReader blockReader = null;
    try {
        blockReader = BlockReaderTestUtil.getBlockReader(cluster, lblock, 0, TEST_FILE_LEN);
        blockReader.readFully(buf, 0, TEST_FILE_LEN);
    } finally {
        if (blockReader != null)
            blockReader.close();
    }
    byte expected[] = DFSTestUtil.calculateFileContentsFromSeed(SEED, TEST_FILE_LEN);
    Assert.assertTrue(Arrays.equals(buf, expected));
    // Another ShortCircuitReplica object should have been created.
    Assert.assertEquals(2, replicasCreated.get());
    dfs.close();
    cluster.shutdown();
    sockDir.close();
}

From source file:org.jboss.pnc.jenkinsbuilddriver.test.JenkinsDriverRemoteTest.java

@Test
//@Ignore("To be fixed by NCL-554")
public void startJenkinsJobTestCase() throws Exception {
    BuildConfigurationAudited pbc = getBuildConfiguration();

    RunningEnvironment runningEnvironment = getRunningEnvironment();

    final Semaphore mutex = new Semaphore(1);
    ObjectWrapper<Boolean> completed = new ObjectWrapper<>(false);
    ObjectWrapper<BuildDriverResult> resultWrapper = new ObjectWrapper<>();
    ObjectWrapper<Long> buildStarted = new ObjectWrapper<>();
    ObjectWrapper<Long> buildTook = new ObjectWrapper<>();

    class BuildTask {
        CompletedBuild buildJobDetails;/*from  ww w  .ja  va 2  s. c om*/
    }

    final BuildTask buildTask = new BuildTask();

    Consumer<CompletedBuild> onComplete = (completedBuild) -> {
        buildTask.buildJobDetails = completedBuild;
        completed.set(true);
        buildTook.set(System.currentTimeMillis() - buildStarted.get());
        log.info("Received build completed in " + buildTook.get() + "ms.");

        try {
            resultWrapper.set(completedBuild.getBuildResult());
        } catch (BuildDriverException e) {
            throw new AssertionError("Cannot get build result.", e);
        }

        mutex.release();
    };

    Consumer<Throwable> onError = (e) -> {
        throw new AssertionError(e);
    };

    mutex.acquire();
    RunningBuild runningBuild = jenkinsBuildDriver.startProjectBuild(mock(BuildExecution.class), pbc,
            runningEnvironment);
    buildStarted.set(System.currentTimeMillis());
    runningBuild.monitor(onComplete, onError);
    mutex.tryAcquire(60, TimeUnit.SECONDS); // wait for callback to release

    Assert.assertTrue("There was no complete callback.", completed.get());
    Assert.assertNotNull(buildTask.buildJobDetails);

    long minBuildTime = 5000;
    Assert.assertTrue(
            "Received build completed in " + buildTook.get() + " while expected >" + minBuildTime + ".",
            buildTook.get() >= minBuildTime);

    BuildDriverResult buildDriverResult = resultWrapper.get();

    Assert.assertEquals(BuildDriverStatus.SUCCESS, buildDriverResult.getBuildDriverStatus());
    Assert.assertTrue("Incomplete build log.",
            buildDriverResult.getBuildLog().contains("Building in workspace"));
    Assert.assertTrue("Incomplete build log.", buildDriverResult.getBuildLog().contains("Finished: SUCCESS"));

    Assert.assertTrue("There was no complete callback.", completed.get());
}

From source file:org.jboss.pnc.environment.docker.DockerEnvironmentDriverRemoteTest.java

@Test
public void buildDestroyEnvironmentTest() throws EnvironmentDriverException, InterruptedException {
    final Semaphore mutex = new Semaphore(0);

    // Create container
    final DockerStartedEnvironment startedEnv = (DockerStartedEnvironment) dockerEnvDriver
            .buildEnvironment(BuildType.JAVA, DUMMY_REPOSITORY_CONFIGURATION);

    Consumer<RunningEnvironment> onComplete = (generalRunningEnv) -> {
        DockerRunningEnvironment runningEnv = (DockerRunningEnvironment) generalRunningEnv;
        boolean containerDestroyed = false;
        try {/*from  w  w w  . j  ava 2 s  .  co m*/
            testRunningContainer(runningEnv, true, "Environment wasn't successfully built.");
            testRunningEnvContainer(runningEnv, true, "Environment wasn't set up correctly.");

            // Destroy container
            dockerEnvDriver.destroyEnvironment(runningEnv.getId());
            containerDestroyed = true;
            testRunningContainer(runningEnv, false, "Environment wasn't successfully destroyed.");
            mutex.release();
        } catch (Throwable e) {
            fail(e.getMessage());
        } finally {
            if (!containerDestroyed)
                destroyEnvironmentWithReport(runningEnv.getId());
        }
    };

    Consumer<Exception> onError = (e) -> {
        destroyEnvironmentWithReport(startedEnv.getId());
        fail("Failed to init docker container. " + e.getMessage());
    };

    startedEnv.monitorInitialization(onComplete, onError);
    mutex.tryAcquire(MAX_TEST_DURATION, TimeUnit.SECONDS);
}

From source file:org.apache.hadoop.hdfs.client.impl.TestBlockReaderFactory.java

/**
 * When an InterruptedException is sent to a thread calling
 * FileChannel#read, the FileChannel is immediately closed and the
 * thread gets an exception.  This effectively means that we might have
 * someone asynchronously calling close() on the file descriptors we use
 * in BlockReaderLocal.  So when unreferencing a ShortCircuitReplica in
 * ShortCircuitCache#unref, we should check if the FileChannel objects
 * are still open.  If not, we should purge the replica to avoid giving
 * it out to any future readers./*from  w ww .j a  va 2 s  . c o  m*/
 *
 * This is a regression test for HDFS-6227: Short circuit read failed
 * due to ClosedChannelException.
 *
 * Note that you may still get ClosedChannelException errors if two threads
 * are reading from the same replica and an InterruptedException is delivered
 * to one of them.
 */
@Test(timeout = 120000)
public void testPurgingClosedReplicas() throws Exception {
    BlockReaderTestUtil.enableBlockReaderFactoryTracing();
    final AtomicInteger replicasCreated = new AtomicInteger(0);
    final AtomicBoolean testFailed = new AtomicBoolean(false);
    DFSInputStream.tcpReadsDisabledForTesting = true;
    BlockReaderFactory.createShortCircuitReplicaInfoCallback = new ShortCircuitCache.ShortCircuitReplicaCreator() {
        @Override
        public ShortCircuitReplicaInfo createShortCircuitReplicaInfo() {
            replicasCreated.incrementAndGet();
            return null;
        }
    };
    TemporarySocketDirectory sockDir = new TemporarySocketDirectory();
    Configuration conf = createShortCircuitConf("testPurgingClosedReplicas", sockDir);
    final MiniDFSCluster cluster = new MiniDFSCluster.Builder(conf).numDataNodes(1).build();
    cluster.waitActive();
    final DistributedFileSystem dfs = cluster.getFileSystem();
    final String TEST_FILE = "/test_file";
    final int TEST_FILE_LEN = 4095;
    final int SEED = 0xFADE0;
    final DistributedFileSystem fs = (DistributedFileSystem) FileSystem.get(cluster.getURI(0), conf);
    DFSTestUtil.createFile(fs, new Path(TEST_FILE), TEST_FILE_LEN, (short) 1, SEED);

    final Semaphore sem = new Semaphore(0);
    final List<LocatedBlock> locatedBlocks = cluster.getNameNode().getRpcServer()
            .getBlockLocations(TEST_FILE, 0, TEST_FILE_LEN).getLocatedBlocks();
    final LocatedBlock lblock = locatedBlocks.get(0); // first block
    final byte[] buf = new byte[TEST_FILE_LEN];
    Runnable readerRunnable = new Runnable() {
        @Override
        public void run() {
            try {
                while (true) {
                    BlockReader blockReader = null;
                    try {
                        blockReader = BlockReaderTestUtil.getBlockReader(cluster.getFileSystem(), lblock, 0,
                                TEST_FILE_LEN);
                        sem.release();
                        try {
                            blockReader.readAll(buf, 0, TEST_FILE_LEN);
                        } finally {
                            sem.acquireUninterruptibly();
                        }
                    } catch (ClosedByInterruptException e) {
                        LOG.info("got the expected ClosedByInterruptException", e);
                        sem.release();
                        break;
                    } finally {
                        if (blockReader != null)
                            blockReader.close();
                    }
                    LOG.info("read another " + TEST_FILE_LEN + " bytes.");
                }
            } catch (Throwable t) {
                LOG.error("getBlockReader failure", t);
                testFailed.set(true);
                sem.release();
            }
        }
    };
    Thread thread = new Thread(readerRunnable);
    thread.start();

    // While the thread is reading, send it interrupts.
    // These should trigger a ClosedChannelException.
    while (thread.isAlive()) {
        sem.acquireUninterruptibly();
        thread.interrupt();
        sem.release();
    }
    Assert.assertFalse(testFailed.get());

    // We should be able to read from the file without
    // getting a ClosedChannelException.
    BlockReader blockReader = null;
    try {
        blockReader = BlockReaderTestUtil.getBlockReader(cluster.getFileSystem(), lblock, 0, TEST_FILE_LEN);
        blockReader.readFully(buf, 0, TEST_FILE_LEN);
    } finally {
        if (blockReader != null)
            blockReader.close();
    }
    byte expected[] = DFSTestUtil.calculateFileContentsFromSeed(SEED, TEST_FILE_LEN);
    Assert.assertTrue(Arrays.equals(buf, expected));

    // Another ShortCircuitReplica object should have been created.
    Assert.assertEquals(2, replicasCreated.get());

    dfs.close();
    cluster.shutdown();
    sockDir.close();
}

From source file:fr.xebia.management.statistics.ProfileAspect.java

@Around(value = "execution(* *(..)) && @annotation(profiled)", argNames = "pjp,profiled")
public Object profileInvocation(ProceedingJoinPoint pjp, Profiled profiled) throws Throwable {

    logger.trace("> profileInvocation({},{}", pjp, profiled);

    MethodSignature jointPointSignature = (MethodSignature) pjp.getStaticPart().getSignature();

    // COMPUTE SERVICE STATISTICS NAME
    Expression nameAsExpression = profiledMethodNameAsExpressionByMethod.get(jointPointSignature.getMethod());
    if (nameAsExpression == null) {
        if (StringUtils.hasLength(profiled.name())) {
            String nameAsStringExpression = profiled.name();
            nameAsExpression = expressionParser.parseExpression(nameAsStringExpression, parserContext);
        } else {/*from w  w w.j a  va  2 s. c om*/
            String fullyQualifiedMethodName = getFullyQualifiedMethodName(//
                    jointPointSignature.getDeclaringTypeName(), //
                    jointPointSignature.getName(), //
                    this.classNameStyle);
            nameAsExpression = new LiteralExpression(fullyQualifiedMethodName);
        }
    }

    String serviceStatisticsName;
    if (nameAsExpression instanceof LiteralExpression) {
        // Optimization : prevent useless objects instantiations
        serviceStatisticsName = nameAsExpression.getExpressionString();
    } else {
        serviceStatisticsName = nameAsExpression.getValue(new RootObject(pjp), String.class);
    }

    // LOOKUP SERVICE STATISTICS
    ServiceStatistics serviceStatistics = serviceStatisticsByName.get(serviceStatisticsName);

    if (serviceStatistics == null) {
        // INSTIANCIATE NEW SERVICE STATISTICS
        ServiceStatistics newServiceStatistics = new ServiceStatistics(//
                new ObjectName(this.jmxDomain + ":type=ServiceStatistics,name=" + serviceStatisticsName), //
                profiled.businessExceptionsTypes(), profiled.communicationExceptionsTypes());

        newServiceStatistics.setSlowInvocationThresholdInMillis(profiled.slowInvocationThresholdInMillis());
        newServiceStatistics
                .setVerySlowInvocationThresholdInMillis(profiled.verySlowInvocationThresholdInMillis());
        int maxActive;
        if (StringUtils.hasLength(profiled.maxActiveExpression())) {
            maxActive = expressionParser.parseExpression(profiled.maxActiveExpression(), parserContext)
                    .getValue(new RootObject(pjp), Integer.class);
        } else {
            maxActive = profiled.maxActive();
        }
        newServiceStatistics.setMaxActive(maxActive);
        newServiceStatistics.setMaxActiveSemaphoreAcquisitionMaxTimeInNanos(TimeUnit.NANOSECONDS
                .convert(profiled.maxActiveSemaphoreAcquisitionMaxTimeInMillis(), TimeUnit.MILLISECONDS));

        ServiceStatistics previousServiceStatistics = serviceStatisticsByName.putIfAbsent(serviceStatisticsName,
                newServiceStatistics);
        if (previousServiceStatistics == null) {
            serviceStatistics = newServiceStatistics;
            mbeanExporter.registerManagedResource(serviceStatistics);
        } else {
            serviceStatistics = previousServiceStatistics;
        }
    }

    // INVOKE AND PROFILE INVOCATION
    long nanosBefore = System.nanoTime();

    Semaphore semaphore = serviceStatistics.getMaxActiveSemaphore();
    if (semaphore != null) {
        boolean acquired = semaphore.tryAcquire(
                serviceStatistics.getMaxActiveSemaphoreAcquisitionMaxTimeInNanos(), TimeUnit.NANOSECONDS);
        if (!acquired) {
            serviceStatistics.incrementServiceUnavailableExceptionCount();
            throw new ServiceUnavailableException("Service '" + serviceStatisticsName + "' is unavailable: "
                    + serviceStatistics.getCurrentActive() + " invocations of are currently running");
        }
    }
    serviceStatistics.incrementCurrentActiveCount();
    try {

        Object returned = pjp.proceed();

        return returned;
    } catch (Throwable t) {
        serviceStatistics.incrementExceptionCount(t);
        throw t;
    } finally {
        if (semaphore != null) {
            semaphore.release();
        }
        serviceStatistics.decrementCurrentActiveCount();
        long deltaInNanos = System.nanoTime() - nanosBefore;
        serviceStatistics.incrementInvocationCounterAndTotalDurationWithNanos(deltaInNanos);
        if (logger.isDebugEnabled()) {
            logger.debug("< profileInvocation({}): {}ns", serviceStatisticsName, deltaInNanos);
        }
    }
}

From source file:org.mahasen.node.MahasenNodeManager.java

/**
 * Insert past object into DHT//from  w  w w  .j  a va 2 s. c  o m
 * @param resourceId
 * @param resource
 * @throws InterruptedException
 * @throws PastException
 */
public void insertIntoDHT(final Id resourceId, MahasenResource resource, boolean isToUpdate)
        throws InterruptedException, PastException {
    MahasenPastContent myContent = new MahasenPastContent(resourceId, resource);
    myContent.setIsToUpdate(isToUpdate);
    //  String result = this.lookupDHT(resourceId);
    final Semaphore control = new Semaphore(0);

    System.out.println(" storing key for" + resource.getId() + "  :" + myContent.getId());

    {

        mahasenPastApp.insert(myContent, new Continuation<Boolean[], Exception>() {
            // the result is an Array of Booleans for each insert
            public void receiveResult(Boolean[] results) {

                int numSuccessfulStores = 0;

                for (int ctr = 0; ctr < results.length; ctr++) {
                    if (results[ctr].booleanValue())
                        numSuccessfulStores++;
                }
                control.release();
                System.out.println(" successfully stored at " + +numSuccessfulStores + " locations.");
            }

            public void receiveException(Exception result) {

                System.out.println("Error storing ");
                result.printStackTrace();
                control.release();

            }
        });

    }

}

From source file:com.parse.ParseConfigTest.java

@Test
public void testGetInBackgroundWithCallbackSuccess() throws Exception {
    final Map<String, Object> params = new HashMap<>();
    params.put("string", "value");

    ParseConfig config = new ParseConfig(params);
    ParseConfigController controller = mockParseConfigControllerWithResponse(config);
    ParseCorePlugins.getInstance().registerConfigController(controller);

    final Semaphore done = new Semaphore(0);
    ParseConfig.getInBackground(new ConfigCallback() {
        @Override/*from  ww  w  . j  a  v  a 2s. c  om*/
        public void done(ParseConfig config, ParseException e) {
            assertEquals(1, config.params.size());
            assertEquals("value", config.params.get("string"));
            done.release();
        }
    });

    // Make sure the callback is called
    assertTrue(done.tryAcquire(1, 10, TimeUnit.SECONDS));
    verify(controller, times(1)).getAsync(anyString());
}

From source file:com.parse.ParseConfigTest.java

@Test
public void testGetInBackgroundWithCallbackFail() throws Exception {
    ParseException exception = new ParseException(ParseException.CONNECTION_FAILED, "error");
    ParseConfigController controller = mockParseConfigControllerWithException(exception);
    ParseCorePlugins.getInstance().registerConfigController(controller);

    final Semaphore done = new Semaphore(0);
    ParseConfig.getInBackground(new ConfigCallback() {
        @Override//from w  ww.  ja va 2s  . com
        public void done(ParseConfig config, ParseException e) {
            assertEquals(ParseException.CONNECTION_FAILED, e.getCode());
            assertEquals("error", e.getMessage());
            done.release();
        }
    });

    // Make sure the callback is called
    assertTrue(done.tryAcquire(1, 10, TimeUnit.SECONDS));
    verify(controller, times(1)).getAsync(anyString());
}

From source file:com.bt.aloha.collections.memory.InMemoryHousekeepingCollectionImpl.java

public void housekeep() {
    try {/*  w  w  w.  j a va2 s .c om*/
        log.info(String.format("Housekeeping: info table size is %d", size()));

        List<String> expiredNotDead = new ArrayList<String>();
        for (String id : getAll().keySet()) {
            Semaphore s = getSemaphores().get(id);
            s.acquire();
            try {
                T info = getAll().get(id);
                log.info(String.format(
                        "Housekeeping: trying to housekeep info %s (forced=%s, expired=%s, dead=%s, TTL=%d)",
                        id, info.isHousekeepForced(), isExpired(info), info.isDead(), maxTimeToLive));
                if (isExpired(info) || info.isHousekeepForced())
                    if (info.isDead() || info.isHousekeepForced()) {
                        log.info(String.format("Housekeeping: found an 'old' info, removing: %s", id));
                        getAll().remove(id);
                        getSemaphores().remove(id);
                    } else
                        expiredNotDead.add(id);
                else
                    log.debug(String
                            .format("Housekeeping: info %s has not expired yet and will not be housekept", id));
            } catch (Throwable t) {
                log.error("Error processing Info object during housekeeping: ", t);
            } finally {
                s.release();
            }
        }
        // if we have expired objects which are not dead then prepare them for housekeeping
        for (final String expiredInfoId : expiredNotDead) {
            try {
                T expiredInfo = get(expiredInfoId);
                String beanName = expiredInfo.getSimpleSipBeanId();
                log.info(String.format("Housekeeping: preparing an info %s for being housekept by %s",
                        expiredInfoId, beanName));
                HousekeeperAware creatorBean = (HousekeeperAware) applicationContext.getBean(beanName);
                creatorBean.killHousekeeperCandidate(expiredInfoId);
            } catch (Throwable t) {
                log.error(String.format(
                        "Unable to kill housekeeper candidate %s...will still remove from collection next housekeep",
                        expiredInfoId), t);
            } finally {
                //force housekeeping next time for that object
                ConcurrentUpdateBlock concurrentUpdateBlock = new ConcurrentUpdateBlock() {
                    public void execute() {
                        log.info(String.format("Housekeeping: setting housekeepForced flag to true in info %s",
                                expiredInfoId));
                        T info = get(expiredInfoId);
                        info.setHousekeepForced(true);
                        replace(info);
                    }

                    public String getResourceId() {
                        return expiredInfoId;
                    }
                };
                concurrentUpdateManager.executeConcurrentUpdate(concurrentUpdateBlock);
            }
        }
    } catch (Throwable t) {
        log.error("Error processing timer callback", t);
    }
}

From source file:org.apache.hadoop.hbase.procedure2.TestProcedureExecutor.java

@Test(timeout = 60000)
public void testWorkerStuck() throws Exception {
    // replace the executor
    final Configuration conf = new Configuration(htu.getConfiguration());
    conf.setFloat("hbase.procedure.worker.add.stuck.percentage", 0.5f);
    conf.setInt("hbase.procedure.worker.monitor.interval.msec", 500);
    conf.setInt("hbase.procedure.worker.stuck.threshold.msec", 750);

    final int NUM_THREADS = 2;
    createNewExecutor(conf, NUM_THREADS);

    Semaphore latch1 = new Semaphore(2);
    latch1.acquire(2);/*from  w  w  w .j a  v  a  2s .  com*/
    BusyWaitProcedure busyProc1 = new BusyWaitProcedure(latch1);

    Semaphore latch2 = new Semaphore(2);
    latch2.acquire(2);
    BusyWaitProcedure busyProc2 = new BusyWaitProcedure(latch2);

    long busyProcId1 = procExecutor.submitProcedure(busyProc1);
    long busyProcId2 = procExecutor.submitProcedure(busyProc2);
    long otherProcId = procExecutor.submitProcedure(new NoopProcedure());

    // wait until a new worker is being created
    int threads1 = waitThreadCount(NUM_THREADS + 1);
    LOG.info("new threads got created: " + (threads1 - NUM_THREADS));
    assertEquals(NUM_THREADS + 1, threads1);

    ProcedureTestingUtility.waitProcedure(procExecutor, otherProcId);
    assertEquals(true, procExecutor.isFinished(otherProcId));
    ProcedureTestingUtility.assertProcNotFailed(procExecutor, otherProcId);

    assertEquals(true, procExecutor.isRunning());
    assertEquals(false, procExecutor.isFinished(busyProcId1));
    assertEquals(false, procExecutor.isFinished(busyProcId2));

    // terminate the busy procedures
    latch1.release();
    latch2.release();

    LOG.info("set keep alive and wait threads being removed");
    procExecutor.setKeepAliveTime(500L, TimeUnit.MILLISECONDS);
    int threads2 = waitThreadCount(NUM_THREADS);
    LOG.info("threads got removed: " + (threads1 - threads2));
    assertEquals(NUM_THREADS, threads2);

    // terminate the busy procedures
    latch1.release();
    latch2.release();

    // wait for all procs to complete
    ProcedureTestingUtility.waitProcedure(procExecutor, busyProcId1);
    ProcedureTestingUtility.waitProcedure(procExecutor, busyProcId2);
    ProcedureTestingUtility.assertProcNotFailed(procExecutor, busyProcId1);
    ProcedureTestingUtility.assertProcNotFailed(procExecutor, busyProcId2);
}