簡體   English   中英

Java 中關於 RejectedExecutionException 的初學者問題

[英]A beginner' question about RejectedExecutionException in Java

最近開始基於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();
          }
        }
        }
      }
    }

每次運行都會出現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)
 

代碼摘自Thing in Java (4th),我初步猜測是驅動main()的隱式線程在所有任務提交之前執行shutdown() ,因為第一個任務執行成功且異常信息表明pool size= 1 ,但這是不可能的,因為 main() 中的所有內容都是按順序執行的。 所有 Callable 對象都應在關閉前提交。

然后我將 ThreadPool 的類型更改為Executors.newFixedThreadPool(10) ,仍然發生異常並且池大小仍然為 1。

這怎么發生的?

如果您更仔細地查看您的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();
    }
  }
}

請注意,查詢每個Futurefor循環嵌套在提交任務的for循環中。 這意味着您提交一個任務,等待結果,關閉執行程序,然后嘗試提交另一個任務。 以下應該可以解決您的問題:

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

我移動了executor.shutdown()調用,因為這只需要發生一次,在您提交最后一個任務之后。 當然,如果您要繼續重用執行程序,那么您不會想要關閉它。

我還將System.out.println(e)更改為e.printStackTrace() 通常最好打印堆棧跟蹤,而不僅僅是打印異常類型和消息(默認情況下,這是Throwable#toString()返回的內容)。 在像您的示例這樣的短程序中可能並不明顯,但堆棧跟蹤在更復雜的應用程序中非常有價值,因為它直接指向引發異常的位置。 請參閱什么是堆棧跟蹤,以及如何使用它來調試我的應用程序錯誤? 了解更多信息。

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