在這裡Java的方法中有執行緒遞迴,不懂得用什麼方法求執行時間遇到一個有趣的問題,多執行緒掃描資料夾求執行時間。一般這種掃描資料夾耗時好像都是用的遞迴遍歷一下進行計時,頭一次看到這種一個資料夾一個執行緒的,這裡按照原問題樓主的想法試著解決一下。
剛開始我是採用靜態變數,共享總耗時,把每個run方法耗時都加上。
package com.brewin.codetuning.test;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ThreadDemo02
{
public static void main(String args[]) {
File file=new File("D:\\AA");
MyThread mt1 = new MyThread("執行緒1",file);
mt1.start();
}
}
class MyThread extends Thread
{
private String name;
private File file;
public static int sum;
static {
sum = 0;
}
public MyThread(String name,File file) {
this.name = name;
this.file=file;
}
@Override
public void run() {
long startTime = System.currentTimeMillis();
File[] files=file.listFiles();
if(files!=null &&files.length>0) {
for(File f:files) {
if(f.isDirectory()) {
new MyThread(f.getName(),f).start();
}
// 列印檔名不方便看最後的耗時列印,註釋掉
// else {
// System.out.println(Thread.currentThread().getName()+":"+f);
// }
}
}
// try {
// Thread.sleep(5000);
// }
// catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
long endTime = System.currentTimeMillis();
long usedTime = (endTime-startTime);
sum+=usedTime;
System.out.println(name + " 執行結束,耗時: "+usedTime+" ms,sum現為:" +MyThread.sum+" ms");
}
}
控制檯列印的什麼呢?下面擷取最後一部分
storage 執行結束,耗時: 0 ms,sum現為:3156 ms
x509 執行結束,耗時: 1 ms,sum現為:3157 ms
implementations 執行結束,耗時: 1 ms,sum現為:3158 ms
implementations 執行結束,耗時: 1 ms,sum現為:3159 ms
但是實際並沒有用到3秒多,很快就結束了。
下面是加了Thread.sleep(5000)的結果,更明顯一些:
xs 執行結束,耗時: 5004 ms,sum現為:2611580 ms
implementations 執行結束,耗時: 5001 ms,sum現為:2606576 ms
traversers 執行結束,耗時: 5001 ms,sum現為:2616581 ms
多執行緒是併發執行,所以這個思路是錯誤的,不能計算他們的總和,而是要計算他們的最開始的時間和最後的時間。改變思路,在最開始時初始化一個開始時間,後面每次執行緒結束後都更新一下最後時間,求他們之間的差值就可以了。
package com.brewin.codetuning.test;
import java.io.File;
public class ThreadDemo02
{
public static void main(String args[]) {
File file=new File("D:\\AA");
MyThread mt1 = new MyThread("執行緒1",file);
mt1.start();
}
}
class MyThread extends Thread
{
private static long startTime;
private String name;
private File file;
static {
startTime = System.currentTimeMillis();
}
public MyThread(String name,File file) {
this.name = name;
this.file=file;
}
@Override
public void run() {
File[] files=file.listFiles();
if(files!=null &&files.length>0) {
for(File f:files) {
if(f.isDirectory()) {
new MyThread(f.getName(),f).start();
}
// 列印檔名不方便看最後的耗時列印,註釋掉
// }else {
// System.out.println(Thread.currentThread().getName()+":"+f);
// }
}
}
long usedTime = System.currentTimeMillis()-startTime;
System.out.println(name + " 執行結束,已耗時: "+usedTime+" ms");
}
}
控制檯最後一段列印如下:
io 執行結束,已耗時: 164 ms
proxy 執行結束,已耗時: 164 ms
dom 執行結束,已耗時: 164 ms
serialize 執行結束,已耗時: 165 ms
fsm 執行結束,已耗時: 165 ms
rmi 執行結束,已耗時: 166 ms
spi 執行結束,已耗時: 166 ms
tree 執行結束,已耗時: 166 ms
graph 執行結束,已耗時: 166 ms
util 執行結束,已耗時: 166 ms
utils 執行結束,已耗時: 167 ms
protocol 執行結束,已耗時: 167 ms
implementations 執行結束,已耗時: 167 ms
http 執行結束,已耗時: 167 ms
content 執行結束,已耗時: 167 ms
resolver 執行結束,已耗時: 167 ms
util 執行結束,已耗時: 168 ms
identity 執行結束,已耗時: 168 ms
keyvalues 執行結束,已耗時: 168 ms
x509 執行結束,已耗時: 169 ms
xs 執行結束,已耗時: 169 ms
serializer 執行結束,已耗時: 169 ms
util 執行結束,已耗時: 169 ms
xs 執行結束,已耗時: 169 ms
util 執行結束,已耗時: 169 ms
validation 執行結束,已耗時: 170 ms
undo 執行結束,已耗時: 170 ms
traversers 執行結束,已耗時: 170 ms
util 執行結束,已耗時: 170 ms
namingutil 執行結束,已耗時: 170 ms
exceptions 執行結束,已耗時: 170 ms
CORBA 執行結束,已耗時: 171 ms
xpath 執行結束,已耗時: 171 ms
transforms 執行結束,已耗時: 171 ms
utils 執行結束,已耗時: 171 ms
params 執行結束,已耗時: 171 ms
encryption 執行結束,已耗時: 171 ms
signature 執行結束,已耗時: 171 ms
output 執行結束,已耗時: 171 ms
implementations 執行結束,已耗時: 172 ms
closure 執行結束,已耗時: 172 ms
concurrent 執行結束,已耗時: 172 ms
orbutil 執行結束,已耗時: 172 ms
helper 執行結束,已耗時: 172 ms
keyresolver 執行結束,已耗時: 172 ms
storage 執行結束,已耗時: 172 ms
implementations 執行結束,已耗時: 173 ms
implementations 執行結束,已耗時: 173 ms
resolver 執行結束,已耗時: 173 ms
implementations 執行結束,已耗時: 173 ms
models 執行結束,已耗時: 174 ms
implementations 執行結束,已耗時: 174 ms
opti 執行結束,已耗時: 174 ms
text 執行結束,已耗時: 174 ms
rtf 執行結束,已耗時: 174 ms
utils 執行結束,已耗時: 175 ms
giopmsgheaders 執行結束,已耗時: 175 ms
reference 執行結束,已耗時: 175 ms
regex 執行結束,已耗時: 175 ms
threadpool 執行結束,已耗時: 175 ms
res 執行結束,已耗時: 176 ms
html 執行結束,已耗時: 177 ms
parser 執行結束,已耗時: 177 ms
看到原問題樓主有提到CountDownLatch ,找來文章看了一下,不是很適合這裡,CountDownLatch計數器的初始大小要跟任務數的大小一致(跟執行緒數無關),每執行一次任務,計數器減一(countDown),await()方法會一直阻塞主執行緒,直到計數器的值減為0,才會釋放鎖,如此便可以達到確保所有任務都完成才繼續下一步的效果。
但是本文場景是不斷遞迴new出新執行緒,並且本文場景中要求任務數和執行緒數是相等的,無法確定任務數,就沒辦法初始化CountDownLatch 大小。
想要用CountDownLatch 的話只能加個統計方法,獲得資料夾數量,如下:
package com.brewin.codetuning.test;
import java.io.File;
import java.util.concurrent.CountDownLatch;
public class ThreadDemo02
{
static int count;
static {
count = 0;
}
public static void main(String args[]) {
File file = new File("D:\\AA");
countNumberOfFolders(file);
long startTime = System.currentTimeMillis();
MyThread mt1 = new MyThread("執行緒1", file);
mt1.start();
try {
MyThread.latch.await();
}
catch (InterruptedException e) {
e.printStackTrace();
}
long usedTime = System.currentTimeMillis() - startTime;
System.out.println("耗時: " + usedTime + " ms");
}
/**
* 統計資料夾數量
* @param f
* @exception/throws [違例型別] [違例說明]
* @see [類、類#方法、類#成員]
*/
public static void countNumberOfFolders(File f) {
count++;
File[] files = f.listFiles();
if (files != null && files.length > 0) {
for (File file : files) {
if (file.isDirectory()) {
countNumberOfFolders(file);
}
}
}
}
}
class MyThread extends Thread
{
private String name;
private File file;
static CountDownLatch latch;
static {
latch = new CountDownLatch(ThreadDemo02.count);
}
public MyThread(String name, File file) {
this.name = name;
this.file = file;
}
@Override
public void run() {
File[] files = file.listFiles();
if (files != null && files.length > 0) {
for (File f : files) {
if (f.isDirectory()) {
new MyThread(f.getName(), f).start();
}
// 列印檔名不方便看最後的耗時列印,註釋掉
// }else {
// System.out.println(Thread.currentThread().getName()+":"+f);
// }
}
}
System.out.println(name + " 執行結束");
latch.countDown();
}
}
結果如下:
http 執行結束
output 執行結束
dom 執行結束
compiler 執行結束
util 執行結束
耗時: 350 ms
可以看到確實是等到所有的執行緒執行結束後才進行的下一步。
如上 結題
本作品採用《CC 協議》,轉載必須註明作者和本文連結