当前位置: 首页 > 知识库问答 >
问题:

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

钮博裕
2023-03-14

我正在尝试同时向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上使用泽西。这是文件的处理方式。

论资源

@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类是

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客户端上传了数百个文件,每次都有效。但是对于并发请求,对于任何一个文件(第一个),都会多次调用此上传()方法。

共有1个答案

萧元徽
2023-03-14

尝试了你的代码,似乎效果不错。顺便说一下,不需要将路径映射到文件,因为使用文件。复制您可以轻松地将路径的内容复制到输出流

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

您还可以放弃和“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....");
}

 类似资料:
  • Java 是最先支持多线程开发的语言之一, Java 多线程和并发也是 Java 学习的重点加难点。本教程根据作者多年 Java 开发经验总结而成,旨在帮助读者明白并发的原理。

  • 本文向大家介绍使用java的HttpClient实现多线程并发,包括了使用java的HttpClient实现多线程并发的使用技巧和注意事项,需要的朋友参考一下 说明:以下的代码基于httpclient4.5.2实现。 我们要使用java的HttpClient实现get请求抓取网页是一件比较容易实现的工作: 要多线程执行get请求时上面的方法也堪用。不过这种多线程请求是基于在每次调用get方法时创建

  • 本文向大家介绍Java多线程并发编程 并发三大要素,包括了Java多线程并发编程 并发三大要素的使用技巧和注意事项,需要的朋友参考一下 一、原子性 原子,一个不可再被分割的颗粒。原子性,指的是一个或多个不能再被分割的操作。 int i = 1; // 原子操作 i++; // 非原子操作,从主内存读取 i 到线程工作内存,进行 +1,再把 i 写到朱内存。 虽然读取和写入都是原子操作,但合起来就不

  • 本文向大家介绍java并发包中CountDownLatch和线程池的使用详解,包括了java并发包中CountDownLatch和线程池的使用详解的使用技巧和注意事项,需要的朋友参考一下 1.CountDownLatch 现在做的这个华为云TaurusDB比赛中,参考的之前参加过阿里的PolarDB大赛的两个大佬的代码,发现都有用到CountDownLatch这个类,之前看代码的时候也看过,但是没

  • 并发是什么?引用Rob Pike的经典描述: 并发是同一时间应对多件事情的能力 其实在我们身边就有很多并发的事情,比如一边上课,一边发短信;一边给小孩喂奶,一边看电视,只要你细心留意,就会发现许多类似的事。相应地,在软件的世界里,我们也会发现这样的事,比如一边写博客,一边听音乐;一边看网页,一边下载软件等等。显而易见这样会节约不少时间,干更多的事。然而一开始计算机系统并不能同时处理两件事,这明显满

  • 我需要将邮件从我的gmail帐户发送到另一个帐户。我使用了以下代码。 但我得到的错误如下。。。javax。邮政MessaginException:无法连接到SMTP主机:SMTP。gmail。com,端口:25 我该怎么解决这个问题。你能帮我吗?