System.nanoTime()计算异常?FTP客户端耗时统计不符问题排查
问题分析:System.nanoTime()统计耗时与实际不符的原因及解决办法
嘿,我看了你代码里的问题,这事儿其实是任务重试时的状态变量没重置导致的,咱们一步步拆解清楚:
问题成因
先理清楚你的代码逻辑里的坑:
- 你用了成员变量
starttime、startflag来记录开始时间,而且startflag在第一次赋值starttime后就被设为false了。 - 所有catch块里都调用了
start()方法——我猜这个方法是用来重启你的AsyncTask对吧? - 当程序因为连接异常(比如UnknownHostException)重试时,
startflag还是false,所以新任务不会重新赋值starttime,一直用第一次任务启动时的旧值。 - 最后某次任务成功传输完成(
finflag=true)时,endtime是这次成功任务的结束时间,用它减去第一次任务的starttime,自然就把中间所有重试等待的时间都算进去了——这就是为什么统计出来是18秒,但实际成功传输只用了2秒。
另外还有个小问题:endtime放在doInBackground的最末尾,不管任务成功失败都会赋值,但只有成功时才会在onPostExecute里计算耗时。如果中间有多次失败重试,endtime会被覆盖,但starttime一直是第一次的旧值,结果就把所有重试的时间都累加进去了。
解决办法
咱们从两个核心点入手,确保每次任务的时间统计都是独立的:
1. 每次启动任务时重置所有状态变量
在你的start()方法里,把统计相关的变量全部重置,保证新任务从头开始统计:
public void start() { // 重置状态,彻底避免跨任务的状态污染 startflag = true; finflag = false; starttime = 0; endtime = 0; // 这里放启动AsyncTask的代码,比如new YourAsyncTask().execute(); }
2. 把时间统计的时机调整到核心传输逻辑内
不要依赖startflag控制starttime的赋值,而是在成功建立连接并开始处理文件传输的瞬间记录开始时间,在传输完成(收到Finished)的瞬间记录结束时间:
修改doInBackground里的代码:
while(true) { socket = new Socket(ipadd, port); // 在这里直接记录开始时间,不用依赖外部状态变量 starttime = System.nanoTime(); br = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedOutputStream bo = new BufferedOutputStream(socket.getOutputStream()); PrintWriter pw = new PrintWriter(bo, true); file = br.readLine(); if (file.equals("Finished")) { // ... 你的现有代码(读取datas、关闭流等) finflag=true; // 在这里记录结束时间,确保是传输完成的瞬间 endtime = System.nanoTime(); break; } // ... 文件传输的逻辑 }
3. (可选)避免成员变量跨任务污染
如果可以的话,把starttime和endtime改成doInBackground内的局部变量,只在当前任务中生效,这样就不会被其他重试任务影响了。不过因为你需要在onPostExecute里用这些值,所以可以把它们作为任务的返回值传递,或者用静态内部类封装任务状态。
验证修改
修改后,每次重试任务都会重新记录starttime,只有成功传输的那次任务的时间差会被计算,这样统计出来的时长就和实际传输时间完全一致了。
内容的提问来源于stack exchange,提问作者sumanth




