我想知道是否基于Java本身(我怀疑,因为我已经检查过了),或者其他可靠的地方(例如Apache Commons)提供此功能,或者是否必须编写自己的代码。最好使用轻量级的框架。我不介意自己编写代码,但如果有“标准”版本存在,我至少想先看一下。
看一下瓜娃子(RateLimiter):
速率限制器。在概念上,速率限制器按可配置的速率分发许可证。每次调用 acquire() 都会阻塞,直到有一个许可证可用,然后获取它。获取到许可证后,不需要释放。速率限制器通常用于限制对某个物理或逻辑资源的访问速率。这与 Semaphore 不同,后者限制并发访问数量而不是速率(尽管并发和速率密切相关,例如,参见 Little's Law)。
它是线程安全的,但仍然带有 @Beta
标志。 无论如何,值得一试。
您需要将每个调用包装在关于速率限制器的方面。 对于更清晰的解决方案,您可以为 ExecutorService
创建某种包装器。
来自 javadoc:
final RateLimiter rateLimiter = RateLimiter.create(2.0); // rate is "2 permits per second"
void submitTasks(List<Runnable> tasks, Executor executor) {
for (Runnable task : tasks) {
rateLimiter.acquire(); // may wait
executor.execute(task);
}
}
public void run() {
// ...
requestLimiter.acquire();
connection.send();
// ...
}
同时,您需要安排一个(单个)次要线程定期释放已获取的资源(例如每60秒一次):
public void run() {
// ...
requestLimiter.drainPermits(); // make sure not more than max are released by draining the Semaphore empty
requestLimiter.release(MAX_NUM_REQUESTS);
// ...
}
new ThrottlingExecutor().setThrottlingRule(new MaxPerSecond(100))
这样的代码会是一个相当干净的解决方案。 - mrip每秒最多只能处理100个任务--如果提交的任务超过100个,则应该将它们排队并稍后执行
您需要查看Executors.newFixedThreadPool(int limit)
。这将允许您限制可以同时执行的线程数。如果提交多个线程,它们将被排队并稍后执行。
ExecutorService threadPool = Executors.newFixedThreadPool(100);
Future<?> result1 = threadPool.submit(runnable1);
Future<?> result2 = threadPool.submit(runnable2);
Futurte<SomeClass> result3 = threadPool.submit(callable1);
...
Executor
处理任务的速率。 - chrylis -cautiouslyoptimistic-根据情况,正如之前的回答所建议的那样,ThreadPoolExecutor的基本功能可能会有所帮助。
但是,如果线程池被多个客户端共享,并且您想要限制每个客户端的使用以确保一个客户端不会使用所有线程,则BoundedExecutor将起到作用。
更多细节可以在以下示例中找到:
个人认为这种情况非常有趣。在我的情况下,我想强调的是有趣的阻塞阶段是消费方面的,就像经典的生产者/消费者并发理论一样。这与之前提出的一些建议答案相反。也就是说,我们不想阻塞提交线程,而是基于速率(任务/秒)策略阻塞消费线程。因此,即使队列中有准备好的任务,执行/消费线程也可能会阻塞等待满足限制策略。
话虽如此,我认为一个很好的选择是Executors.newScheduledThreadPool(int corePoolSize)。这样,您需要在执行器前面放置一个简单的队列(一个简单的LinkedBlockingQueue就可以),然后安排定期任务从队列中获取实际任务(ScheduledExecutorService.scheduleAtFixedRate)。因此,这不是一个直接的解决方案,但如果您尝试像之前讨论的那样限制消费者,它应该表现得足够好。
可以在Runnable内部进行限制:
public static Runnable throttle (Runnable realRunner, long delay) {
Runnable throttleRunner = new Runnable() {
// whether is waiting to run
private boolean _isWaiting = false;
// target time to run realRunner
private long _timeToRun;
// specified delay time to wait
private long _delay = delay;
// Runnable that has the real task to run
private Runnable _realRunner = realRunner;
@Override
public void run() {
// current time
long now;
synchronized (this) {
// another thread is waiting, skip
if (_isWaiting) return;
now = System.currentTimeMillis();
// update time to run
// do not update it each time since
// you do not want to postpone it unlimited
_timeToRun = now+_delay;
// set waiting status
_isWaiting = true;
}
try {
Thread.sleep(_timeToRun-now);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// clear waiting status before run
_isWaiting = false;
// do the real task
_realRunner.run();
}
}};
return throttleRunner;
}
从JAVA 线程去抖动和节流中获取
@Beta
有点烦人,但还是很不错的。 - mrip