List <future>当尝试从Future

时间:2017-11-01 13:26:29

标签: java multithreading future executorservice callable

此问题类似于以下现有问题。我知道IndexOutOfBoundsExceptionRuntimeException,因此很明显代码中存在错误。

traversing a List<Future> object throws IndexOutOfBounds exception

在我的情况下,此异常实际发生在实际传输文件的API中。它会被call()(Lambda)捕获并被视为失败以进行重试。

java项目中有各种文件传输任务。因此,我使用ExecutorService来满足要求。

有一个文件列表,每个文件将从这些文件提供给ExecutorService,我传递 Callable ,如果传输失败,最终会返回文件对象。

我知道我一定做错了。

请建议需要做哪些更改,感谢您的时间。

如果需要任何其他信息,请告诉我。

(用虚拟名称替换真实的类和方法名称)

异常堆栈跟踪

java.util.concurrent.ExecutionException: java.lang.IndexOutOfBoundsException: Index: 2, Size: 1
    at java.util.concurrent.FutureTask.report(FutureTask.java:122)
    at java.util.concurrent.FutureTask.get(FutureTask.java:192)
    at FileTransfer.lambda$transfer$1(FileTransfer.java)
    at java.util.ArrayList.forEach(ArrayList.java:1249)
    at FileTransfer.transfer(FileTransfer.java)
Caused by: java.lang.IndexOutOfBoundsException: Index: 2, Size: 1
    at java.util.LinkedList.checkElementIndex(LinkedList.java:555)
    at java.util.LinkedList.get(LinkedList.java:476)
    at com.autofixrt.errorhandler.strategy.retry.FileTransfer.lambda$transfer$0(FileTransfer.java)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

以下是正在进行文件传输操作的java方法。

FileTransfer.java

public class FileTransfer {
    public boolean transfer(List<File> fileList) {

            final int size = fileList.size();

            final int[] pos = {0};
            // Also tried with AtomicInteger but gives the same IndexOutOfBoundsException

            final ExecutorService executor = ExecutorUtil.createDefaultExecutor();

            final List<Future<File>> futureList = new ArrayList<>();

            try {

                while (pos[0] < size) {

                    final Future<File> future = executor.submit(() -> {

                        File failed = null;

                        // Exception caused by at below line
                        // Caused by: java.lang.IndexOutOfBoundsException: Index: 2, Size: 1
                        final File input = fileList.get(pos[0]++); // caused by

                        try {

                            final boolean isSuccess = // API call to transfer file;

                            if (!isSuccess)
                                failed = input;

                        } catch (final Exception e) {

                            failed = input;
                        }
                        return failed;

                    }); // submit ends

                    futureList.add(future);

                } // while ends

                final List<File> failedList = new ArrayList<>(0);

                // iterate over list of futures collected above
                futureList.forEach(f -> {

                    try {

                        // java.util.concurrent.ExecutionException: java.lang.IndexOutOfBoundsException: Index: 2, Size: 1
                        final File input = f.get(); // Exception occures at this line

                        if (input != null)
                            failedList.add(input);

                    } catch (Exception e) {
                        System.out.println("Error in retrieving failed from future");
                        e.printStackTrace();
                    }
                });

            } finally {
                ExecutorUtil.shutdown(executor);
                futureList.clear();
            }


            boolean success = true;
            // send failed email, if still failed present
            if (!isEmpty(failed)) {
                success = false;
                // sendErrorEmail(failedList);
            }

            return success;
    }
}

ExecutorUtil.java

public final class ExecutorUtil {

    private ExecutorUtil() { }

    private static final int DEFAULT_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2;

    public static ExecutorService createDefaultExecutor() {
        return createExecutor(DEFAULT_THREAD_POOL_SIZE);
    }

    private static ExecutorService createExecutor(int threadPoolSize) {
        return Executors.newFixedThreadPool(threadPoolSize);
    }

    public static void shutdown(ExecutorService executor) {

        if (isNull(executor))
            return;

        executor.shutdown(); // Disable new tasks from being submitted

        try {

            // Wait 20 seconds for existing tasks to terminate
            if (!executor.awaitTermination(20L, TimeUnit.SECONDS)) {

                executor.shutdownNow(); // Cancel currently executing tasks

                // Wait 10 seconds for tasks to respond to being cancelled
                if (!executor.awaitTermination(10L, TimeUnit.SECONDS))

                    System.out.println("Pool did not terminate");

                else
                    System.out.println("Thread pool has been shutdown");

            } else
                System.out.println("Thread pool has been shutdown - no await");


        } catch (InterruptedException e) {

            // (Re-)Cancel if current thread also interrupted
            executor.shutdownNow();
        }
    }
}

1 个答案:

答案 0 :(得分:-1)

  1. 您的int[0]不是线程安全的。请改用AtomicInteger
  2. 您的条件while (i < size)在主线程上执行,而增量i++在执行程序线程上完成。可能的执行是:

    i = 0;
    while (i < 1) //true
    executor.submit(...)
    //note that i hasn't been incremented yet
    while (i < 1) //true
    i++; //in the first executor thread
    executor.submit(...) //IOOBE
    
  3. 我想知道你为什么不写信:

    for (File f : fileList) {
      executor.submit( ... ); //use f directly in the executor
    }