简体   繁体   English

Java 中关于 RejectedExecutionException 的初学者问题

[英]A beginner' question about RejectedExecutionException in Java

Recently I begin to learn concurrency based on Java, I run the following code on windows (jdk 11)最近开始基于Java学习并发,我在windows(jdk 11)上运行如下代码

import java.util.*;
import java.util.concurrent.*;

class TaskWithResult implements Callable<String>{
      private int id;
      public TaskWithResult(int id){
        this.id = id;
      }
      public String call(){
        return  "Result of TaskWithResult "+id;
      }
    }

    public class TestCallable{
      public static void main(String[] args){
        ExecutorService exec = Executors.newCachedThreadPool();
        ArrayList<Future<String>> results = 
          new ArrayList<Future<String>>();
        for(int i = 0;i<10;i++){
          results.add(exec.submit(new TaskWithResult(i)));
        for(Future<String> fs:results){
          try{
            System.out.println(fs.get());
          }catch(InterruptedException e){
            System.out.println(e);
            return;
          }catch(ExecutionException e){
            System.out.println(e);
          }finally{
            exec.shutdown();
          }
        }
        }
      }
    }

The sanme Exception occurs everytime I run it:每次运行都会出现sanme异常:

\\output:
Result of TaskWithResult 0
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@380fb434[Not completed, task = me.rexjz.a.TaskWithResult@21bcffb5] rejected from java.util.concurrent.ThreadPoolExecutor@3cda1055[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 1]
    at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2055)
    at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:825)
    at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1355)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140)
    at javaBin/me.rexjz.a.TestCallable.main(TestCallable.java:22)
 

The code is excerpted from Thinging in Java (4th),I initially guess the implicit thread which drives main() execute shutdown() before all the tasks are submitted because the first task is succeessfully executed and the Exeception information indicates that pool size= 1 , but it is impossible because everything in main() is sequentially executed.代码摘自Thing in Java (4th),我初步猜测是驱动main()的隐式线程在所有任务提交之前执行shutdown() ,因为第一个任务执行成功且异常信息表明pool size= 1 ,但这是不可能的,因为 main() 中的所有内容都是按顺序执行的。 All the Callable objects should be submitted before shutdown.所有 Callable 对象都应在关闭前提交。

Then I change the type of ThreadPool to Executors.newFixedThreadPool(10) , the Exception stil occured and the pool size is still 1.然后我将 ThreadPool 的类型更改为Executors.newFixedThreadPool(10) ,仍然发生异常并且池大小仍然为 1。

How did this happen?这怎么发生的?

If you look at your for loops a little more closely you'll see the problem (especially once the code is conventionally indented):如果您更仔细地查看您的for循环,您会发现问题(尤其是在代码按常规缩进的情况下):

for (int i = 0; i < 10; i++) {
  results.add(exec.submit(new TaskWithResult(i)));
  for (Future<String> fs : results) {
    try {
      System.out.println(fs.get());
    } catch (InterruptedException e) {
      System.out.println(e);
      return;
    } catch (ExecutionException e) {
      System.out.println(e);
    } finally {
      exec.shutdown();
    }
  }
}

Notice that the for loop which queries each Future is nested within the for loop which submits the tasks.请注意,查询每个Futurefor循环嵌套在提交任务的for循环中。 That means you submit one task, wait for the result, shutdown the executor , and then attempt to submit another task.这意味着您提交一个任务,等待结果,关闭执行程序,然后尝试提交另一个任务。 The following should fix your problem:以下应该可以解决您的问题:

for (int i = 0; i < 10; i++) {
  results.add(exec.submit(new TaskWithResult(i)));
}

executor.shutdown(); // shutdown() allows already-submitted tasks to execute

for (Future<String> fs : results) {
  try {
    System.out.println(fs.get());
  } catch (InterruptedException e) {
    e.printStackTrace();
    return;
  } catch (ExecutionException e) {
    e.printStackTrace();
  }
}

I moved the executor.shutdown() call since that only needs to happen once, after you've submitted the last task.我移动了executor.shutdown()调用,因为这只需要发生一次,在您提交最后一个任务之后。 Of course, if you're going to keep reusing the executor then you would not want to shut it down.当然,如果您要继续重用执行程序,那么您不会想要关闭它。

I also changed System.out.println(e) to e.printStackTrace() .我还将System.out.println(e)更改为e.printStackTrace() It's typically better to print the stack trace rather than just the exception type and message (which is what Throwable#toString() returns, by default).通常最好打印堆栈跟踪,而不仅仅是打印异常类型和消息(默认情况下,这是Throwable#toString()返回的内容)。 It may not be obvious in a short program like your example, but the stack trace is extremely valuable in more complicated applications since it points you directly to where the exception was thrown.在像您的示例这样的短程序中可能并不明显,但堆栈跟踪在更复杂的应用程序中非常有价值,因为它直接指向引发异常的位置。 See What is a stack trace, and how can I use it to debug my application errors?请参阅什么是堆栈跟踪,以及如何使用它来调试我的应用程序错误? for more information.了解更多信息。

package com.springboot.testapplication;

import java.util.*;
import java.util.concurrent.*;

class TaskWithResult implements Callable<String> {
    private int id;

    public TaskWithResult(int id) {
        this.id = id;
    }

    public String call() {
        return "Result of TaskWithResult " + id;
    }
}

public class TestCallable {
    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();
        ArrayList<Future<String>> results = new ArrayList<Future<String>>();
        for (int i = 0; i < 10; i++) {
            results.add(exec.submit(new TaskWithResult(i)));
        }
        for (Future<String> fs : results) {
            try {
                System.out.println(fs.get());
            } catch (InterruptedException e) {
                System.out.println(e);
                return;
            } catch (ExecutionException e) {
                System.out.println(e);
            } finally {
                exec.shutdown();
            }
        }

    }
}

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

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