Probably one of the best of options would be to use Semaphore http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html class and give it 80 permits every minute. This can be accomplished for example by using timer class http://docs.oracle.com/javase/7/docs/api/java/util/Timer.html. The caller thread will consume permits every time it performs the call to the service by calling acquire() on the semaphore, which will block if all permits have been drained already.
It would of course be possible to code this up using wait/notify and integer counter with timer or separate thread, as you mention, but that would be more complex compared to the usage of more modern java.util.concurrent API that I have outlined above.
It can look close to the following:
class Throttler implements TimerTask {
final Semaphore s = new Semaphore(80);
final Timer timer = new Timer(true);
Throttler() {
timer.schedule(this, 0, 60*1000); //schedule this for 1 min execution
}
run() { //called by timer
s.release(80 - s.availablePermits());
}
makeCall() {
s.acquire();
doMakeCall();
}
}
This should work starting from Java 5.
Also even nicer solution would be to use com.google.common.util.concurrent.RateLimiter
from Guava. It can look like this:
class Throttler {
final RateLimiter rateLimiter = RateLimiter.create(80.0/60.0);
makeCall() {
rateLimiter.acquire();
doMakeCall();
}
}
Semantics is slightly different compared to Semaphore solution, with RateLimiter being most probably better fit in your situation.