【发布时间】:2020-12-21 15:14:32
【问题描述】:
我们有一个从多个线程调用并访问外部数据库的方法。为了不减慢其他客户端的数据库速度,对该方法的调用应限制为 1 次/秒。
我喜欢保持简单,所以我这样做了:
private static final Object SYNC_LOCK = new Object();
public static double myMethod(int param1, ...) {
synchronized(SYNC_LOCK) {
//do something...
Thread.sleep(1000);
return result;
}
}
现在,我们正在使用 sonarqube 进行代码分析,这种睡眠被视为“阻塞”错误。 通过查看代码,我可以排除死锁。实现一种基于令牌的方法对我来说似乎有点多。
您是否同意 sonarqube 需要更改此代码?
现在,我们可以使用例如线程池来实现如下所述。但对我来说,第一个例子似乎更圆滑。
private static ExecutorService es = Executors.newFixedThreadPool(1);
private static long lastCall = 0;
public static Double myMethod(int param1, ...) {
Future<Double> f = es.submit(new Callable<Double>() {
@Override
public Double call() throws Exception {
long diff = System.currentTimeMillis() - lastCall;
if (diff < 1000) {
long sleepMillis = 1000 - diff;
Thread.sleep(sleepMillis);
}
//do something...
lastCall = System.currentTimeMillis();
return result;
}
});
try {
return f.get();
} catch (InterruptedException | ExecutionException e) {
//handle this
return null;
}
}
【问题讨论】:
-
你让线程在方法中休眠?
-
是的,因为强迫调用者等待是个坏主意。
-
休眠在计算上并不昂贵,那么为什么该方法在工作完成时要休眠呢?同步可以防止多个线程同时调用该方法,因此这已经将其限制为单线程操作。这还不够吗?
-
Kayaman 是对的,请解释一下“1 call/second”的用途。 SonarQube 也是对的,
Thread.sleep在那里看起来像废话。由于 SonarQube 不是人类,我怀疑它是否可以“理解”原因,如果有的话。 -
添加睡眠正是因为它的计算成本不高。关键是,对该方法的请求突发不会对应用程序的其他部分产生不良的性能影响。
标签: java concurrency synchronization