我正在尝试使用线程下载与某个模式匹配的多个文件。该模式可能匹配1个、5个或10个不同大小的文件。
假设实际下载文件的代码在downloadFile()方法中,fileNames是匹配该模式的文件名列表。如何使用线程完成这个任务?每个线程将只下载一个文件。是否建议在for循环内创建新线程?
for (String name : fileNames){
downloadFile(name, toPath);
}
我正在尝试使用线程下载与某个模式匹配的多个文件。该模式可能匹配1个、5个或10个不同大小的文件。
假设实际下载文件的代码在downloadFile()方法中,fileNames是匹配该模式的文件名列表。如何使用线程完成这个任务?每个线程将只下载一个文件。是否建议在for循环内创建新线程?
for (String name : fileNames){
downloadFile(name, toPath);
}
你真的希望使用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
异常。
是的,你可以在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)
创建的线程池中。
Executors.newFixedThreadPool(int)
并查看@Phillip Reichart的答案。 - maerics是的,您可以在代码中创建线程。
for (final String name : fileNames){
new Thread() {
public void run() {
downloadFile(name, toPath);
}
}.start();
}
使用Executor,试一下吧。
ExecutorService exec= Executors.newCachedThreadPool()
for (String name : fileNames){
exec.submit(new Runnable()
{
public void run()
{
downloadFile(name, toPath);
}
});
}
Executors.newFixedThreadPool(3)
execute()
Runnable
时会阻塞,你应该调用exec.submit()
:) - Philipp ReichartExecute.execute()
可能会“在新线程中、在池化线程中或在调用线程中执行,由 Executor 实现自行决定。”你真的想将变量声明为 ExecutorService
并使用 submit()
。 - Philipp Reichartexecute()
可能会在调用线程上运行命令,而显然存在一种不会出现这个问题的方法,这是一个相当有说服力的理由。 - Philipp Reichart所有上述方法都会创建线程,但实际上并没有实现并发。
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");
fileNames
有多少个,该怎么办呢?我的意思是用户可能会选择在页面1中下载单个文件,然后在页面3或5中再次下载。我想控制异步下载任务的数量上限为n。 - Alston