com.tencent.angel.utils.Sleeper Maven / Gradle / Ivy
The newest version!
/*
* Tencent is pleased to support the open source community by making Angel available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed 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
*
* https://opensource.org/licenses/Apache-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 com.tencent.angel.utils;
import com.tencent.angel.Stoppable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Sleeper for current thread. Sleeps for passed period. Also checks passed boolean and if
* interrupted, will return if the flag is set (rather than go back to sleep until its sleep time is
* up).
*/
public class Sleeper {
private final Logger LOG = LoggerFactory.getLogger(this.getClass().getName());
private final int period;
private final Stoppable stopper;
private static final long MINIMAL_DELTA_FOR_LOGGING = 10000;
private final Object sleepLock = new Object();
private volatile boolean triggerWake = false;
/**
* @param sleep sleep time in milliseconds
* @param stopper When {@link Stoppable#isStopped()} is true, this thread will cleanup and exit
* cleanly.
*/
public Sleeper(final int sleep, final Stoppable stopper) {
this.period = sleep;
this.stopper = stopper;
}
/**
* Sleep for period.
*/
public void sleep() {
sleep(System.currentTimeMillis());
}
/**
* If currently asleep, stops sleeping; if not asleep, will skip the next sleep cycle.
*/
public void skipSleepCycle() {
synchronized (sleepLock) {
triggerWake = true;
sleepLock.notifyAll();
}
}
/**
* Sleep for period adjusted by passed startTime
*
* @param startTime Time some task started previous to now. Time to sleep will be docked current
* time minus passed startTime.
*/
public void sleep(final long startTime) {
if (this.stopper.isStopped()) {
return;
}
long now = System.currentTimeMillis();
long waitTime = this.period - (now - startTime);
if (waitTime > this.period) {
LOG.warn("Calculated wait time > " + this.period + "; setting to this.period: " + System
.currentTimeMillis() + ", " + startTime);
waitTime = this.period;
}
while (waitTime > 0) {
long woke = -1;
try {
synchronized (sleepLock) {
if (triggerWake)
break;
sleepLock.wait(waitTime);
}
woke = System.currentTimeMillis();
long slept = woke - now;
if (slept - this.period > MINIMAL_DELTA_FOR_LOGGING) {
LOG.warn("We slept " + slept + "ms instead of " + this.period
+ "ms, this is likely due to a long "
+ "garbage collecting pause and it's usually bad, see "
+ "http://hbase.apache.org/book.html#trouble.rs.runtime.zkexpired");
}
} catch (InterruptedException iex) {
// We we interrupted because we're meant to stop? If not, just
// continue ignoring the interruption
if (this.stopper.isStopped()) {
return;
}
}
// Recalculate waitTime.
woke = (woke == -1) ? System.currentTimeMillis() : woke;
waitTime = this.period - (woke - startTime);
}
triggerWake = false;
}
}