开发人员面临的最困难的任务之一是查找和诊断生产中运行缓慢的代码。
首先,您如何监控生产代码而不放慢速度? 当然,您无法通过分析器运行生产代码。 即使您具有计时代码的机制,那么如何诊断问题呢? 如果您无法在开发环境中重现该问题,则尤其如此。 理想情况下,您希望在生产中发生问题时得到通知,并向其提供足够的信息,以便有合理的机会修复或至少诊断问题。
这是我的同事彼得·劳瑞 ( Peter Lawrey)建议的一种机制,您可以用来精确地做到这一点。 (完整的代码清单可在此处找到)。
您要做的是创建一个Monitor类,如下所示:
public class Monitor implements Runnable{
private final Thread thread;
private final AtomicLong startTime
= new AtomicLong(Long.MAX_VALUE);
private final int thresholdMS;
public Monitor(Thread thread, int thresholdMS){
this.thread = thread;
this.thresholdMS = thresholdMS;
}
public void reset(){
startTime.set(System.currentTimeMillis());
}
@Override
public void run(){
while(thread.isAlive()){
long timeTaken = System.currentTimeMillis()-startTime.get();
if(timeTaken > thresholdMS){
System.out.println(timeTaken + "-------------------------");
Stream.of(thread.getStackTrace())
.forEach(System.out::println);
}
try {
Thread.sleep(thresholdMS/2);
} catch (InterruptedException e) {
break;
}
}
}
}
如果线程无法在阈值时间内重置,则此类将转储正在运行的线程的堆栈跟踪。
这是一些示例程序,演示如何调用Monitor。
Monitor monitor = new Monitor(Thread.currentThread(), 8);
Thread thread = new Thread(monitor, "MonitorThread");
thread.setDaemon(true);
thread.start();
while(true) {
monitor.reset();
double x=0;
for (int i = 0; i < 10_000; i++) {
x += Math.sqrt(i);
Logger.getLogger(getClass().getName()).fine("x=" + x);
}
}
Monitor
观察到了这一“关键”代码。 如果在8毫秒内未重置监视器,它将转储代码的堆栈跟踪。
如果您有一个Monitor监视您的关键代码段,则可以确保它们在给定的约束范围内执行。 如果代码确实违反了约束,则可以通过检查堆栈跟踪来很好地了解问题所在。 您还可以使用它来查看关键代码在其运行期间未执行多少次。
如果您没有专用的备用CPU进行监控,则可以更改等待时间。 另外,您可能想更改等待策略以允许GC暂停,这会影响所有线程。 您可能想通过使用System.nanoTime()
来细化计时,而不是以毫秒为单位。
翻译自: https://www.javacodegeeks.com/2015/02/detect-diagnose-slow-code-production.html