2011-09-21 36 views
12

我想下載使用線程匹配模式的多個文件。該模式可以匹配1或5或10個差異文件。java下載使用線程的多個文件

可以說爲了簡單起見,下載文件的實際代碼是在downloadFile()方法中,fileNames是與該模式匹配的文件名列表。我如何使用線程來做到這一點。每個線程只會下載一個文件。建議在for循環中創建一個新線程。

for (String name : fileNames){ 
    downloadFile(name, toPath); 
} 

回答

31

你真的想用一個ExecutorService而不是單獨的線程,它是乾淨多了,有可能更高性能,將使你更輕鬆地後改變的事情上(線程數,線程名等):

ExecutorService pool = Executors.newFixedThreadPool(10); 
for (String name : fileNames) { 
    pool.submit(new DownloadTask(name, toPath)); 
} 
pool.shutdown(); 
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS); 
// all tasks have now finished (unless an exception is thrown above) 

而且在你的類別處定義實際工作馬DownloadTask

private static class DownloadTask implements Runnable { 

    private String name; 
    private final String toPath; 

    public DownloadTask(String name, String toPath) { 
     this.name = name; 
     this.toPath = toPath; 
    } 

    @Override 
    public void run() { 
     // surround with try-catch if downloadFile() throws something 
     downloadFile(name, toPath); 
    } 
} 

shutdown()方法有一個非常混亂的名字,因爲它「將使以前提交的任務,以終止之前執行」。 awaitTermination()聲明您需要處理的InterruptedException

+0

這需要'downloadFile()'方法在'DownloadTask'(我的推薦)中定義,或者在外部聲明'static'。 –

+0

'@Philipp Reichart'發佈'shutdown'後,新的下載任務將不會被游泳池接受。如果我是你,我會避免這種情況。 – Bitmap

+0

這是一個沒有問題的問題,因爲在這種情況下關閉後沒有任何新任務添加到池中。第一個代碼片段應該存在於一個方法中,並在每次調用時創建一個新池。 –

1

是的,你可以創建內聯線程。

for (final String name : fileNames){ 
    new Thread() { 
     public void run() { 
      downloadFile(name, toPath); 
     } 
    }.start(); 
} 
5

是的,你當然可以在for循環中創建一個新的線程。事情是這樣的:

List<Thread> threads = new ArrayList<Thread>(); 
for (String name : fileNames) { 
    Thread t = new Thread() { 
    @Override public void run() { downloadFile(name, toPath); } 
    }; 
    t.start(); 
    threads.add(t); 
} 
for (Thread t : threads) { 
    t.join(); 
} 
// Now all files are downloaded. 

你也應該考慮使用Executor,例如,由Executors.newFixedThreadPool(int)創建一個線程池。

+0

使用上面的代碼,我怎麼能限制同時下載的數量,說我只想一次下載3個文件。你有一個使用Executor – user373201

+0

@ user373201的例子:按照我提供給'Executors.newFixedThreadPool(int)'的鏈接並查看@Phillip Reichart的答案。 – maerics

1

使用Executor,試試這個。

ExecutorService exec= Executors.newCachedThreadPool() 
for (String name : fileNames){ 
exec.submit(new Runnable() 
{ 
    public void run() 
    { 
    downloadFile(name, toPath); 
    } 
}); 
} 

如果你想要說的三個下載同時運行,你可以使用:

Executors.newFixedThreadPool(3) 
+0

現在它阻塞while execute()'Runnable',你打算叫'exec.submit()':) –

+0

@Philipp Reichart你真的知道你在說什麼嗎?執行時阻止什麼?聽着布魯夫!當你不知道你在說什麼時,避免標記人。 – Bitmap

+0

是的,我確實曾經被這一次咬過。 ['Execute.execute()'](http://download.oracle.com/javase/1,5.0/docs/api/java/util/concurrent/Executor.html#execute(java.lang.Runnable))may 「...在Executor實現的判斷下,在新線程,共用線程或調用線程**中執行。「你真的想聲明變量爲'ExecutorService'並使用['submit()'](http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html#提交(java.lang.Runnable))。 –

0

所有上述提到的方法創建線程,但實際Concurreny沒有實現。

ExecutorService pool = Executors.newFixedThreadPool(5); 
final File folder = new File("YOUR_FILES_PATH"); 
int l = folder.listFiles().length; 
System.out.println("Total Files----"+folder.listFiles().length); 
long timeStartFuture = Calendar.getInstance().getTimeInMillis(); 
    pool.execute(new DownloadFile(folder,0,l/2)); 
    pool.execute(new DownloadFile(folder,(l/2),l)); 
    pool.shutdown(); 
    try { 
     pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    long timeEndFuture = Calendar.getInstance().getTimeInMillis(); 
    long timeNeededFuture = timeEndFuture - timeStartFuture; 
    System.out.println("Parallel calculated in " + timeNeededFuture + " ms"); 

上述程序用於實現併發性,並請修改按您的要求。