首页 > 解决方案 > Java 多线程示例 - 对象是否共享

问题描述

我对以下示例有疑问。我们有一个主类,它必须从 Web 服务器下载许多文件以及DownloadTask谁来完成这项工作。每个循环都有一个对象saveToMain.java覆盖。该对象DownloadTask在构造函数中作为引用传递给该循环。获取此DownloadTask对象并对其进行一些处理。

  1. saveTo在可以处理之前,是否可以在 main 方法的 for 循环中覆盖对象DownloadTask

    1.1 为什么可以/为什么不能。循环中的对象创建如何工作?

  2. 如果这样做会有所不同:

...
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;
                }
            }

谢谢!

标签: javamultithreadingobject

解决方案


循环中的对象创建如何工作?

它的工作方式与在其他任何地方的工作方式完全相同。表达式的每次计算new File(...)都会导致从堆中分配一个类的新实例File,它会导致使用...参数调用构造函数,并返回对新File实例的引用。

您的代码示例在循环的每次迭代中创建一个新File实例,并将对它的引用存储在saveTo局部变量中,覆盖saveTo. 该分配对新实例saveTo没有任何影响,并且先前引用的实例没有任何影响。FileFilesaveTo

唯一使用的地方saveTo是下一行:

...f = completionService.submit(new DownloadTask(..., saveTo));

因此,分配给的唯一效果saveTo是确定File将哪个实例提供给DownloadTask您的程序创建的每个新实例。

如果 [ 的声明saveTo移出循环,会有所不同吗?]

它不会对您的程序运行方式产生任何影响。无论哪种情况,编译器都会发出相同的代码。不过,这可能会影响其他程序员阅读您的代码的难易程度。当有人看到saveTo在循环体内声明了它for时,他们就不需要浪费任何时间来查看它可能在哪里使用如果您在循环内声明它,那么 Java 将不允许您在循环外使用它。


推荐阅读