【问题标题】:How can we convert a callable into a runnable我们如何将可调用对象转换为可运行对象
【发布时间】:2016-08-15 03:02:07
【问题描述】:

我有一个实现可调用接口的类。我想使用 ScheduledExecutorService 接口的 scheduleAtFixedRate 方法为该类安排一个任务。然而 scheduleAtFixedRate 需要一个可运行的对象作为它可以调度的命令。

因此,我需要某种方法来将可调用对象转换为可运行对象。我尝试了简单的强制转换,但这不起作用。

示例代码:

package org.study.threading.executorDemo;

import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

class ScheduledExecutionTest implements Callable<String> {

    @Override
    public String call() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("inside the call method");
        return null;
    }

}
public class ScheduledExecution {
    public static void main(String[] args) {
        ScheduledExecutorService sec = Executors.newScheduledThreadPool(10);
        sec.scheduleAtFixedRate(new ScheduledExecutionTest(), 5, 2, TimeUnit.SECONDS);
    }
}

【问题讨论】:

  • implements Callable, Runnable 不起作用吗?我以前从未尝试过同时使用这两种方法。
  • Callable 的目的是返回一个值。为什么要以固定速率返回要丢弃的值?
  • 把@PeterLawrey 的评论换一种方式,你想对'Callable`返回的值做什么do

标签: java multithreading runnable callable scheduledexecutorservice


【解决方案1】:

为什么不使用类似的东西:

  final Callable<YourType> callable = ...; // Initialize Callable

  Runnable callableAsRunnable = () -> {
     try {
        callable.call();
     } catch (Exception e) {
        // Handle the exception locally or throw a RuntimeException
     }
  };

【讨论】:

    【解决方案2】:

    假设您真的不需要 Callable 来返回任何有用的东西,您可以将 Callable 包装为 Runnable

    Runnable run = new Runnable() {
        public void run() {
            try {
                Object o = callable.call();
                System.out.println("Returned " + o);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };
    

    或在 Java 8 中

    Runnable run = () -> {
        try {
            Object o = callable.call();
            System.out.println("Returned " + o);
        } catch (Exception e) {
            e.printStackTrace();
        }
    };
    

    这很混乱,但听起来 Callable 一开始就应该是 Runnable,而您不必这样做。

    【讨论】:

      【解决方案3】:

      使用future task,它同时实现了Runnable和callable,你的代码不需要改动太多。

      https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/FutureTask.html

      【讨论】:

        【解决方案4】:
        FutureTask task1 = new FutureTask(Callable<V> callable)
        

        现在这个 task1 可以运行了,因为:

        1. class FutureTask&lt;V&gt; implements RunnableFuture&lt;V&gt;
        2. RunnableFuture&lt;V&gt; extends Runnable, Future&lt;V&gt;

        所以从以上两个关系来看,task1是可运行的,可以在Executor.execute(Runnable)方法中使用

        【讨论】:

        • 虽然 FutureTask 是从 Callable 获取 Runnable 的便捷方式,但请注意,FutureTask 的 JavaDoc 指定计算一旦完成就不能重新开始,这意味着它只能运行一次。鉴于问题是关于向 scheduleAtFixedRate 提供一个 Runnable,它会尝试多次运行,FutureTask 不适合此目的,尽管它在只需要一次执行的其他情况下可能很有用。 JavaDoc 链接:docs.oracle.com/javase/7/docs/api/java/util/concurrent/…
        【解决方案5】:

        JDK 有一个 util 方法可以做到这一点:

        Runnable runnable = ..
        Executors.callable(runnable);
        

        【讨论】:

        • 这与所要求的完全相反
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-02
        • 2017-05-31
        • 2018-09-20
        相关资源
        最近更新 更多