class HalfOpenState<R> extends CircuitState<R> {
  protected final AtomicInteger permittedExecutions = new AtomicInteger();

  public HalfOpenState(CircuitBreakerImpl<R> breaker) {
    super(breaker, CircuitStats.create(breaker, capacityFor(breaker), false, null));
    permittedExecutions.set(capacityFor(breaker));
  }

  @Override
  public boolean tryAcquirePermit() {
    return permittedExecutions.getAndUpdate(permits -> permits == 0 ? 0 : permits - 1) > 0;
  }

  @Override
  public void releasePermit() {
    permittedExecutions.incrementAndGet();
  }

  @Override
  public State getState() {
    return State.HALF_OPEN;
  }

  @Override
  public synchronized void handleConfigChange() {
    stats = CircuitStats.create(breaker, capacityFor(breaker), false, stats);
  }

  /**
   * Checks to determine if a threshold has been met and the circuit should be opened or closed.
   *
   * <p>
   * If a success threshold is configured, the circuit is opened or closed based on whether the ratio was exceeded.
   * <p>
   * Else the circuit is opened or closed based on whether the failure threshold was exceeded.
   */
  @Override
  synchronized void checkThreshold(ExecutionContext<R> context) {<FILL_FUNCTION_BODY>}

  /**
   * Returns the capacity of the breaker in the half-open state.
   */
  private static int capacityFor(CircuitBreaker<?> breaker) {
    int capacity = breaker.getConfig().getSuccessThresholdingCapacity();
    if (capacity == 0)
      capacity = breaker.getConfig().getFailureExecutionThreshold();
    if (capacity == 0)
      capacity = breaker.getConfig().getFailureThresholdingCapacity();
    return capacity;
  }
}

    boolean successesExceeded;
    boolean failuresExceeded;

    int successThreshold = config.getSuccessThreshold();
    if (successThreshold != 0) {
      int successThresholdingCapacity = config.getSuccessThresholdingCapacity();
      successesExceeded = stats.getSuccessCount() >= successThreshold;
      failuresExceeded = stats.getFailureCount() > successThresholdingCapacity - successThreshold;
    } else {
      // Failure rate threshold can only be set for time based thresholding
      int failureRateThreshold = config.getFailureRateThreshold();
      if (failureRateThreshold != 0) {
        // Execution threshold can only be set for time based thresholding
        boolean executionThresholdExceeded = stats.getExecutionCount() >= config.getFailureExecutionThreshold();
        failuresExceeded = executionThresholdExceeded && stats.getFailureRate() >= failureRateThreshold;
        successesExceeded = executionThresholdExceeded && stats.getSuccessRate() > 100 - failureRateThreshold;
      } else {
        int failureThresholdingCapacity = config.getFailureThresholdingCapacity();
        int failureThreshold = config.getFailureThreshold();
        failuresExceeded = stats.getFailureCount() >= failureThreshold;
        successesExceeded = stats.getSuccessCount() > failureThresholdingCapacity - failureThreshold;
      }
    }

    if (successesExceeded)
      breaker.close();
    else if (failuresExceeded)
      breaker.open(context);
  
<methods>public java.time.Duration getRemainingDelay() ,public abstract dev.failsafe.CircuitBreaker.State getState() ,public dev.failsafe.internal.CircuitStats getStats() ,public void handleConfigChange() ,public synchronized void recordFailure(ExecutionContext<R>) ,public synchronized void recordSuccess() <variables>final non-sealed CircuitBreakerImpl<R> breaker,final non-sealed CircuitBreakerConfig<R> config,volatile dev.failsafe.internal.CircuitStats stats