简体   繁体   English

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

[英]Java - Error sending multiple files concurrently using threadpool

I'm trying to send some files to a rest api concurrently. 我正在尝试同时将一些文件发送到rest api。 Tried to implement this answer 试图实现这个答案

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....");

    }
}

I have 10 files in the random directory. 我在random目录中有10个文件。

When I execute this, the first file is sent exactly same number of times as the number of threads I have allocated in Executors.newFixedThreadPool() method. 当我执行此操作时,第一个文件的发送次数与我在Executors.newFixedThreadPool()方法中分配的线程数完全相同。

If I allocate 5 threads, the first file (different in each execution) is sent 5 times, where as rest of the files are sent exactly once! 如果我分配5个线程,则第一个文件(每次执行都不同)将发送5次,而其余文件则仅发送一次! For 10 threads, it is sent 10 times! 对于10个线程,它将发送10次!

How is only one file is sent multiple times, but rest are not? 如何只发送一个文件多次,而其余文件却不发送? What am I doing wrong in the code? 我在代码中做错了什么?

Edit : The api I'm sending the files to is using Jersey on Tomcat 8 . 编辑 :我将文件发送到的api在Tomcat 8上使用Jersey Here's how the files are handled. 这是文件的处理方式。

On resource 在资源上

@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);
    }
}

and the StorageManager class is 并且StorageManager类是

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

For a single file, this works pretty fine. 对于单个文件,这可以正常工作。 I have uploaded hundreds of files using REST clients and this works everytime. 我已经使用REST客户端上传了数百个文件,并且每次都能正常运行。 But for concurrent requests, this upload() method is called a number of times for any one file (first one). 但是对于并发请求,对于任何一个文件(第一个文件)都会多次调用此upload()方法。

Tried your code, seems to work fine. 尝试过您的代码,似乎工作正常。 By the way, there is no need to map the Path to a File because with Files.copy you can easily copy the contents of a Path to an OutputStream . 顺便说一下,不需要将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();
    }
  }
}

You can also ditch the for and the 'while' loops: 您也可以放弃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....");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM