Thread-safe token bucket limiter in Groovy

Groovy
class TokenBucket {
    private final double rate
    private final double capacity
    private double tokens
    private long last = System.nanoTime()
    TokenBucket(double rate, double capacity) { this.rate = rate; this.capacity = capacity; tokens = capacity }
    synchronized boolean tryAcquire(double cost) {
        long now = System.nanoTime()
        tokens = Math.min(capacity, tokens + (now - last) / 1000000000.0d * rate)
        last = now
        if (tokens < cost) return false
        tokens -= cost
        true
    }
}

def bucket = new TokenBucket(2.0d, 3.0d)
println([1, 2, 3, 4].collect { bucket.tryAcquire(1.0d) })