为什么future.get()会卡住?

时间:2015-04-03 12:07:12

标签: java future executorservice

我正在尝试使用invokeAll()方法将文件从客户端并行上传到不同的服务器。这是代码:

List<UploadTask> uploadTasks = new ArrayList<>();
ExecutorService taskExecutor = Executors.newFixedThreadPool(result.size());
for(ClusterElement clusterElement : result)
    uploadTasks.add(new UploadTask(localFile, fileName, clusterElement));
//wait at most 10 seconds for the uploads of the file on all the servers
List<Future<ClusterElement>> uploadResult = taskExecutor.invokeAll(uploadTasks, 13, TimeUnit.MINUTES);
System.out.println("Timeout!");
System.out.println("Printing size " + uploadResult.size());
//after timeout abort all FTPClient (if already finish nothing happens)
for(int i=0;i<uploadResult.size();i++)
{
    Future<ClusterElement> future = uploadResult.get(i);
    ClusterElement clusterElement = result.get(i);
    System.out.println("Result of "+clusterElement.getId()+" cancelled="+future.isCancelled());
    try {
        if(future.isCancelled()) {//if task not finished, then future cancelled (interrupted)
            System.out.println("Deleting file on "+clusterElement.getId());
            removeFile(clusterElement.getAddress(),clusterElement.getPort(),fileName,clusterElement);
        }
        else {
            System.out.println("Getting result...");
            ClusterElement serverUploaded = future.get();//task finished: uploaded complete (or failed)
            if(serverUploaded!=null)//successfully uploaded
            {
                System.out.println("Successfully uploaded on "+serverUploaded.getId());
                servers.add(serverUploaded);
            }
            else
                System.out.println("Uploading failed on "+servers.get(i));
        }
    }catch (ExecutionException e) {
        e.printStackTrace();
    }
}

UploadTask.call()的位置:

@Override
public ClusterElement call() throws Exception {
    ClusterElement result;//null = uploading failed, server where the file was uploaded otherwise
    try (FileInputStream file = new FileInputStream(localFile)) {
        FTPClient ftpClient = SingleClientRequest.createClient(clusterElement.getAddress(),clusterElement.getPort());
        ftpClient.enterLocalPassiveMode();
        System.out.println("Task uploading file on "+clusterElement.getId());
        if(ftpClient.storeFile(fileName+".tmp", file)) {//so the Garbage Collector will not delete it during upload
            ftpClient.rename(fileName + ".tmp", fileName);//rename the file with its real name
            result = clusterElement;
        }
        else {
            System.out.println("File " + fileName + " not uploaded on" + clusterElement.getId());
            result = null;
        }
    } catch (IOException e) {
        System.err.println("Error uploading "+localFile+" on "+clusterElement.getId());
        result = null;
    }
    System.out.println("Returning "+result);
    return result;
}

换句话说,如果文件没有在超时内上传,那么它就会从FS中删除(不幸的是,FTPClient没有为此目的进行任何中止操作,所以我必须在它仍在上传时将其删除)。 / p>

现在的问题是,如果我杀死其中一个服务器,UploadTask.call()会返回null(因为会抛出IOException),所以未来就完成了,所以没有取消。 ..但是当我尝试ClusterElement serverUploaded = future.get();时,它会卡在那里而不是null

为什么会这样?

1 个答案:

答案 0 :(得分:1)

我自己发现问题是由以下原因引起的:

System.out.println("Uploading failed on "+servers.get(i));

因为servers是一个目前为空的列表,而且该进程阻塞了