【问题标题】:java ScheduledFuture getDelay return negative valuejava ScheduledFuture getDelay 返回负值
【发布时间】:2019-03-02 11:32:05
【问题描述】:

我正在使用ScheduledExecutorService、Semaphore 和ScheduledFuture 编写一个限速函数,简单来说,当客户端达到限制时,服务器会返回错误429 并显示“msg please try after %d second”。 我使用 scheduleFuture.getDelay(TimeUnit.SECONDS) 来获取 %d 的值。对于第一次或第二次尝试,它表现正常,即允许访问单元达到限制并显示之后等待多少秒。然后 getDelay 开始显示负值。这是否意味着 ScheduledExecutorService 无法正常工作? 以下是sn-p

public RateLimiter(int permits, long durationInMillis){
    this.semaphore = new Semaphore(permits);
    this.permits = permits;
    this.durationInMillis = durationInMillis;       
    scheduleReplenishment();
}

public boolean allowAccess() {      
    return semaphore.tryAcquire(); 
}

public long nextReplenishmentTime() {
    return scheduledFuture.getDelay(TimeUnit.SECONDS);
}


public void stop() {
    scheduler.shutdownNow();
}   

public void scheduleReplenishment() {
    scheduledFuture = scheduler.schedule(() -> {
        semaphore.release(permits - semaphore.availablePermits());
    }, durationInMillis, TimeUnit.MILLISECONDS);    
}

【问题讨论】:

    标签: java semaphore scheduledexecutorservice


    【解决方案1】:

    如果任务已完成,getDelay(TimeUnit) 将为负数。为了显示它,我在scheduleReplenishment() 中添加了两个参数,并将getReplenishmentTime() 更改为printReplenishmentTime()

    注意1:如果你创建一个Future<>,并用另一个替换一个,你应该关心被删除的......

    注意2:如果要测试Future<>Semaphore,不要立即释放分配的资源。

    private final ConcurrentSkipListMap<String, ScheduledFuture<?>> scheduledFutures
                                        = new ConcurrentSkipListMap<>();
    private final AtomicInteger counter = new AtomicInteger();
    
    public void printReplenishmentTime() {
    
        scheduledFutures.forEach((name, f) -> {
    
            final long delay = f.getDelay(TimeUnit.SECONDS);
            System.out.println(name + " delay " + delay);
        });
    }
    
    /**
     * try acquire one permit once from {@code semaphore}, 
     * then wait {@code waitInMillis}, until all permits used.
     * 
     * @param waitInMillis after successfully used one permit, wait
     * @param permits all permits to use, best if permits @gt; 2
     */
    public void scheduleReplenishment(final long waitInMillis, final int permits) {
    
        final String name = "future" + counter.getAndIncrement();
        scheduledFutures.put(name, scheduler.schedule(() -> {
    
            try {
    
                for (int permit = permits; 0 < permit;) {
    
                    final boolean ack = semaphore.tryAcquire(1);
                    System.out.println(name + " " + (ack ? "acquire" : "not acquire")
                            + " one, but need " + permit);
                    if (ack) {
    
                        permit--;
                    }
                    if (0 < permit) {
    
                        try {
                            Thread.sleep(waitInMillis);
                        } catch (final InterruptedException e) {
    
                            System.out.println(name + " interrupted, exiting...");
                            return;
                        }
                    }
                }
                System.out.println(name + " done");
    
            } finally {
    
                semaphore.release(permits - permit);
            }
    
            // BAD CODE: semaphore.availablePermits() for debugging purposes
            // only, maybe 0 release...
            // semaphore.release(permits - semaphore.availablePermits());
        }, durationInMillis, TimeUnit.MILLISECONDS));
    }
    

    【讨论】:

      【解决方案2】:

      scheduler.schedule() 是一次性函数,这就是为什么它显示负的getDelay() 值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-04-14
        • 1970-01-01
        • 2018-05-07
        • 2020-06-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-10
        相关资源
        最近更新 更多