java - Java 多线程示例 - 对象是否共享
问题描述
我对以下示例有疑问。我们有一个主类,它必须从 Web 服务器下载许多文件以及DownloadTask
谁来完成这项工作。每个循环都有一个对象saveTo
被Main.java
覆盖。该对象DownloadTask
在构造函数中作为引用传递给该循环。获取此DownloadTask
对象并对其进行一些处理。
saveTo
在可以处理之前,是否可以在 main 方法的 for 循环中覆盖对象DownloadTask
?1.1 为什么可以/为什么不能。循环中的对象创建如何工作?
如果这样做会有所不同:
...
for (File fileToDownload: filesToDownload ) {
File saveTo = new File("C:\\temp\\"+fileToDownload.getName());
...
会变成这样:
...
File saveTo;
for (File fileToDownload: filesToDownload ) {
saveTo = new File("C:\\temp\\"+fileToDownload.getName());
...
主.java:
public static void main(String[] args) {
ArrayList<File> filesToDownload = new ArrayList<>();
filesToDownload.add(new File("File1"));
filesToDownload.add(new File("File2"));
filesToDownload.add(new File("File3"));
...
filesToDownload.add(new File("File100"));
ExecutorService pool = Executors.newFixedThreadPool(2);
CompletionService<Boolean> completionService = new ExecutorCompletionService<>(pool);
ArrayList<Future<Boolean>> futures = new ArrayList<>();
for (File fileToDownload: filesToDownload ) {
File saveTo = new File("C:\\temp\\"+fileToDownload.getName());
Future<Boolean> f = completionService.submit(new DownloadTask(new URL("http://1.1.1.1/" + fileToDownload.getName()), saveTo));
futures.add(f);
}
for (int tasks=0;tasks<futures.size();tasks++) {
completionService.take();
}
}
这是 DownloadTask.java:
public class DownloadTask implements Callable<Boolean> {
private URL fileURL;
private File saveTo;
public DownloadTask(URL fileURL, File saveTo) {
this.fileURL = fileURL;
this.saveTo = saveTo;
}
private void downloadFile(URL fileURL, File saveTo) throws IOException {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ReadableByteChannel readableByteChannel = Channels.newChannel(fileURL.openStream());
FileOutputStream fileOutputStream = new FileOutputStream(saveTo);
fileOutputStream.getChannel().transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
fileOutputStream.close();
readableByteChannel.close();
}
@Override
public Boolean call() throws IOException {
downloadFile(fileURL, saveTo);
return true;
}
}
谢谢!
解决方案
循环中的对象创建如何工作?
它的工作方式与在其他任何地方的工作方式完全相同。表达式的每次计算new File(...)
都会导致从堆中分配一个类的新实例File
,它会导致使用...
参数调用构造函数,并返回对新File
实例的引用。
您的代码示例在循环的每次迭代中创建一个新File
实例,并将对它的引用存储在saveTo
局部变量中,覆盖saveTo
. 该分配对新实例saveTo
没有任何影响,并且对先前引用的实例没有任何影响。File
File
saveTo
唯一使用的地方saveTo
是下一行:
...f = completionService.submit(new DownloadTask(..., saveTo));
因此,分配给的唯一效果saveTo
是确定File
将哪个实例提供给DownloadTask
您的程序创建的每个新实例。
如果 [ 的声明
saveTo
移出循环,会有所不同吗?]
它不会对您的程序运行方式产生任何影响。无论哪种情况,编译器都会发出相同的代码。不过,这可能会影响其他程序员阅读您的代码的难易程度。当有人看到saveTo
在循环体内声明了它for
时,他们就不需要浪费任何时间来查看它可能在哪里使用。如果您在循环内声明它,那么 Java 将不允许您在循环外使用它。
推荐阅读
- gitlab-ci - 英特尔代码覆盖率:来自多个 CI 作业的组合代码覆盖率与单独构建的可执行文件
- ruby-on-rails - activeadmin 不允许的参数::subdomain
- javascript - 如何正确输出 json 作为对象
- flutter - 必须是未来的日期:“TZDateTime”的实例
- regex - 如何使用 grafana 对来自 elasticsearch 的唯一值进行分组
- c++ - 如何通过编译标志包含头文件?
- reactjs - 有什么方法可以从反应组件点击事件重定向.net核心控制器方法吗?
- apache-flink - 两种时间连接方式,首选哪一种
- node.js - 如何使用与 webpack 捆绑的 node.js Web 应用程序获取在 OS 上运行的进程列表
- symfony - API 平台 - 有条件的急切加载