blob: 97a73ed207967c325db33827a2df0ed1df5bf1b9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ignite.internal.util;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Allows to execute callback when a set of operations will be completed. Also has an execution counter,
* which allows to block callback execution in case if it is below given threshold. By default, threshold
* is 0 and nothing blocks callback execution.
*
* <p>
* <b>Sample usage:</b>:
* <pre>{@code
* GridCountDownCallback countDownCb = new GridCountDownCallback(
* n, //internal counter is initiated with n
* () -> doSomething() //callback
* );
*
* //each call of countDown() decrements internal counter
* //doSomething() will be executed after counter reaches 0
* for (int i = 0; i < n; i++)
* new Thread(() -> countDownCb.countDown()).start();
* }</pre>
*
* <p>
* <b>Usage with execution threshold:</b>:
* <pre>{@code
* GridCountDownCallback countDownCb = new GridCountDownCallback(
* n, //internal counter is initiated with n
* () -> doSomething(), //callback
* n/2 //execution threshold is initiated with n/2
* );
*
* //a half of calls of countDown() increase execution counter, so it reaches threshold and callback executes.
* //doSomething() will be executed after n threads will perform countDown()
* for (int i = 0; i < n; i++)
* new Thread(() -> countDownCb.countDown(n % 2 == 0)).start();
* }</pre>
*/
public class GridCountDownCallback {
/** */
private final AtomicInteger cntr;
/** */
private final int executionThreshold;
/** */
private final AtomicInteger executionCntr = new AtomicInteger(0);
/** */
private final Runnable cb;
/**
* Constructor.
*
* @param initCnt count of invocations of {@link #countDown}.
* @param cb callback which will be executed after <code>initialCount</code>
* invocations of {@link #countDown}.
* @param executionThreshold minimal count of really performed operations to execute callback.
*/
public GridCountDownCallback(int initCnt, Runnable cb, int executionThreshold) {
cntr = new AtomicInteger(initCnt);
this.executionThreshold = executionThreshold;
this.cb = cb;
}
/**
* Constructor. Execution threshold is set to 0.
*
* @param initCnt count of invocations of {@link #countDown}.
* @param cb callback which will be executed after <code>initialCount</code>
* invocations of {@link #countDown}.
*/
public GridCountDownCallback(int initCnt, Runnable cb) {
this(initCnt, cb, 0);
}
/**
* Decrements the internal counter. If counter becomes 0, callback will be executed.
*
* @param doIncreaseExecutionCounter whether to increase execution counter
*/
public void countDown(boolean doIncreaseExecutionCounter) {
if (doIncreaseExecutionCounter)
executionCntr.incrementAndGet();
if (cntr.decrementAndGet() == 0 && executionCntr.get() >= executionThreshold)
cb.run();
}
/**
* Decrements the internal counter. If counter becomes 0, callback will be executed.
*/
public void countDown() {
countDown(true);
}
}