private DownloadResult download(
      DownloadCheckPoint downloadCheckPoint, DownloadFileRequest downloadFileRequest)
      throws Throwable {
    DownloadResult downloadResult = new DownloadResult();
    ArrayList<PartResult> taskResults = new ArrayList<PartResult>();
    ExecutorService service = Executors.newFixedThreadPool(downloadFileRequest.getTaskNum());
    ArrayList<Future<PartResult>> futures = new ArrayList<Future<PartResult>>();
    List<Task> tasks = new ArrayList<Task>();

    for (int i = 0; i < downloadCheckPoint.downloadParts.size(); i++) {
      if (!downloadCheckPoint.downloadParts.get(i).isCompleted) {
        Task task =
            new Task(
                i, "download-" + i, downloadCheckPoint, i, downloadFileRequest, objectOperation);
        futures.add(service.submit(task));
        tasks.add(task);
      } else {
        taskResults.add(
            new PartResult(
                i + 1,
                downloadCheckPoint.downloadParts.get(i).start,
                downloadCheckPoint.downloadParts.get(i).end));
      }
    }
    service.shutdown();

    service.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);

    for (Future<PartResult> future : futures) {
      try {
        PartResult tr = future.get();
        taskResults.add(tr);
      } catch (ExecutionException e) {
        throw e.getCause();
      }
    }

    Collections.sort(
        taskResults,
        new Comparator<PartResult>() {
          @Override
          public int compare(PartResult p1, PartResult p2) {
            return p1.getNumber() - p2.getNumber();
          }
        });

    downloadResult.setPartResults(taskResults);
    if (tasks.size() > 0) {
      downloadResult.setObjectMetadata(tasks.get(0).GetobjectMetadata());
    }

    return downloadResult;
  }