【问题标题】:ExecutorService.submit() not returning after submitting the taskExecutorService.submit() 提交任务后不返回
【发布时间】:2015-12-12 03:59:56
【问题描述】:

我想对函数进行异步调用并返回而不等待结果(在 Java 中)。我为此编写的代码是:

ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(new Callable<Void>() 
{
    public Void call() throws Exception, TimeoutException {
        hostNetworkSystem.updatePortGroup("Management Network", spec);
        return null;
    }
});

我已经尝试过 Runnable 和 Callable,但是当我在 Eclipse 中通过代码进行调试时,线程卡在 call() 函数并没有在提交任务后立即返回。

我错过了什么吗?

卡在:

    hostNetworkSystem.updatePortGroup("Management Network", spec);

准确地说。我可以看到结果,执行该操作,但它不会从这里返回。

为了更好地理解,整个调用如下所示:

    public void main()
    {
        try {
            AsyncCall asyncCalls = new AsyncCall();
            List<PortGroupData> portData = asyncCalls.updatePortGroupFuture(hostNetworkSystem, portGroupName,
                portGroupData, modelType, oobmStatus, vlanID);
            return portData;
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("InterruptedException " + e.getMessage().toString());
        } catch (ExecutionException e) {
            System.out.println("ExecutionException " + e.getMessage().toString());
            e.printStackTrace();
        } catch (Exception e) {
            System.out.println("Exception " + e.getMessage().toString());
            e.printStackTrace();
        }
    }


    public void updatePortGroupFuture(final HostNetworkSystem hostNetworkSystem,
        final String portGroupName, final NetworkParameters networkData, final String modelType,
        final boolean oobmStatus, int vlanID) throws InterruptedException, ExecutionException, Exception

    {
           <some other actions>
           ExecutorService executorService = Executors.newSingleThreadExecutor();            
           executorService.submit(new Callable<Void>() 
           {
              public Void call() throws Exception, TimeoutException {
              hostNetworkSystem.updatePortGroup("Management Network", spec);
              return null;
           }
          });
          return;
    }

【问题讨论】:

  • 卡在callsubmit?你在某个地方设置了断点吗?您是否尝试过在您的可调用对象中放置一些日志语句,以查看在您运行(而不是调试)应用程序时它是否被调用?

标签: java executorservice futuretask


【解决方案1】:

将代码更改为

Future<Void> future = executorService.submit(new Callable<Void>() 
{
    public Void call() throws Exception, TimeoutException {
        System.out.println("before call");
        hostNetworkSystem.updatePortGroup("Management Network", spec);
        System.out.println("after call");
        return null;
    }
});
      try{
                result = future.get(5000, TimeUnit.MILLISECONDS);
            }catch(TimeoutException e){
                System.out.println("Time out after 5 seconds");
                futureResult.cancel(true);
            }catch(InterruptedException ie){
                System.out.println("Error: Interrupted");
            }catch(ExecutionException ee){
                System.out.println("Error: Execution interrupted");
            }
  1. 如果您得到TimeoutException,请将超时值更改为某个大数字。 检查通话前和通话后的陈述。如果你在调用之前得到而在调用之后没有得到,这意味着发生了一些异常。

  2. 要了解异常,请将submit() 更改为execute() 并捕获异常。

submit() 吞下异常。看看这个code

**Inside FutureTask$Sync**

void innerRun() {
        if (!compareAndSetState(READY, RUNNING))
            return;

      runner = Thread.currentThread();
        if (getState() == RUNNING) { // recheck after setting thread
            V result;
           try {
                result = callable.call();
            } catch (Throwable ex) {
               setException(ex);
                return;
            }
           set(result);
        } else {
            releaseShared(0); // cancel
        }
   }


   protected void setException(Throwable t) {
       sync.innerSetException(t);
   }

看看这个SE Post 和这个 SE 问题:

Choose between ExecutorService's submit and ExecutorService's execute

【讨论】:

    【解决方案2】:

    尝试在 submit(...) 之后放置一个 sysout 并查看它是否被打印出来。这表明父/主线程在 call() 方法上没有被阻塞,并在提交任务后立即返回。

    【讨论】:

      【解决方案3】:

      可以捕获submit方法返回的Future,在submit方法调用后添加如下代码:

              try {
                  future.get();
              }catch(ExecutionException ee){
                  System.out.println("exception >>" + ee.getMessage());
              }
              service.shutdown();
      

      由于future.get是一个阻塞调用,提交任务的线程会等待异步操作完成。您还将了解它是否抛出任何异常。

      FutureTask 将异常存储在一个变量中,然后将其包装在 ExecutionException 中并在调用 get 方法时抛出。所以即使我们在 FutureTask 上调用 get() 方法也能得到底层异常

      【讨论】:

      • 我们不是在寻找阻塞操作。我们只想调用更新并立即返回。因此我没有使用“get()”。
      猜你喜欢
      • 2022-06-11
      • 2016-01-12
      • 2016-09-10
      • 1970-01-01
      • 1970-01-01
      • 2017-10-13
      • 1970-01-01
      • 2018-10-18
      • 1970-01-01
      相关资源
      最近更新 更多