Java - 使用线程池同时发送多个文件时出错

Java - Error sending multiple files concurrently using threadpool

我正在尝试同时将一些文件发送到 rest api。试图实施

public class UploadThread implements Runnable {

    private File file;

    public UploadThread(File file) {
        this.file = file;
    }

    @Override
    public void run() {
        try {
            String url = // api url

            URL server = new URL(url);
            HttpURLConnection connection = (HttpURLConnection) server.openConnection();

            // setting request properties here

            connection.connect();

            OutputStream out = connection.getOutputStream();
            FileInputStream in = new FileInputStream(file);

            try {
              // write to outputstream

            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                out.close();
                in.close();

                if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                    // error handling here
                }

                connection.disconnect();            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class UploadTest {

    public static void main(String[] args) throws Exception {

        List<File> files = Files.walk(Paths.get("/home/random"))
                                .filter(Files::isRegularFile)
                                .map(Path::toFile)
                                .collect(Collectors.toList());

        ExecutorService executorService = Executors.newFixedThreadPool(5);

        for(File file : files) {
            Runnable worker = new UploadThread(file);

            executorService.execute(worker);
        }

        executorService.shutdown();

        while(!executorService.isTerminated()) {
            //
        }

        System.out.println("upload finished....");

    }
}

我在 random 目录中有 10 个文件。

当我执行此操作时,第一个文件的发送次数与我在 Executors.newFixedThreadPool() 方法中分配的线程数完全相同。

如果我分配 5 个线程,第一个文件(每次执行都不同)被发送 5 次,而其余文件只发送一次!对于10个线程,发送10次!

怎么只有一个文件被多次发送,其余的却没有?我在代码中做错了什么?

编辑:我发送文件的 api 在 Tomcat 8 上使用 Jersey。以下是文件的处理方式。

在资源上

@Path("file")
public class MyResource {

    private StorageManager storageManager;

    public MyResource() {
        this.storageManager = new StorageManager();
    }

    @GET
    @Path("upload")
    @Consumes(MediaType.APPLICATION_OCTET_STREAM)
    public Response upload(InputStream inputStream) {
        return this.storageManager.upload(inputStream);
    }
}

StorageManager class 是

public class StorageManager {

    public Response upload(InputStream inputStream) {

        // handling file upload here
        // this method is called 5 or 10 times for one file

        // return some response
    }
}

对于单个文件,这工作得很好。我已经使用 REST 客户端上传了数百个文件,并且每次都有效。但是对于并发请求,此 upload() 方法会为任何一个文件(第一个)调用多次。

试过你的代码,似乎工作正常。顺便说一句,不需要将 Path 映射到 File,因为使用 Files.copy 您可以轻松地将 Path 的内容复制到 OutputStream .

public class UploadThread implements Runnable {

   private Path file;

   public UploadThread(Path file) {
    this.file = Objects.requireNonNull(file);
   }

 @Override
  public void run() {
    try {
        String url = // api url

        URL server = new URL(url);
        HttpURLConnection connection = (HttpURLConnection) server.openConnection();

        // setting request properties here

        connection.connect();

        try (OutputStream out = connection.getOutputStream()) {
            Files.copy(file, out);
          } finally {
            if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                // error handling here
            }

            connection.disconnect(); 
          }           
    } catch (Exception e) {
        e.printStackTrace();
    }
  }
}

您还可以放弃 for 和 'while' 循环:

public static void main(String[] args) throws Exception {
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    Files.walk(Paths.get("/home/random"))
                            .filter(Files::isRegularFile)
                            .map(UploadThread::new)
                            .forEach(executorService::execute);

    executorService.shutdown();
    System.out.println("upload finished....");
}