2011-09-21 56 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"); 

上述程序用于实现并发性,并请修改按您的要求。