7

I have a class which implements the callable interface. I want to schedule a task for the class using scheduleAtFixedRate method of ScheduledExecutorService interface. However scheduleAtFixedRate needs a runnable object as a command which it can schedule.

Hence I need some way in which I can convert a callable to a runnable. I tried simple casting but that is not working.

SAMPLE CODE:

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);
    }
}
Pulkit Gupta
  • 949
  • 2
  • 11
  • 31
  • does `implements Callable, Runnable` not work? I've never tried using both before. – Zircon Apr 21 '16 at 18:28
  • The purpose of a `Callable` is to return a value. Why would you return a value you want to discard at a fixed rate? – Peter Lawrey Apr 21 '16 at 18:29
  • 2
    Putting @PeterLawrey's comment another way, what *do* you want to do with the value returned by the 'Callable`? – dcsohl Apr 21 '16 at 18:33

5 Answers5

12
FutureTask task1 = new FutureTask(Callable<V> callable)

Now this task1 is runnable because:

  1. class FutureTask<V> implements RunnableFuture<V>
  2. RunnableFuture<V> extends Runnable, Future<V>

So from above two relations, task1 is runnable and can be used inside Executor.execute(Runnable) method

Galma88
  • 2,398
  • 6
  • 29
  • 50
pinkman
  • 154
  • 1
  • 5
  • 1
    While FutureTask is a convenient way of obtaining a Runnable from a Callable, note that the JavaDoc for FutureTask specifies that the computation cannot be restarted once completed, meaning it is only valid to run once. Given that the question is about supplying a Runnable to scheduleAtFixedRate, which attempts to run multiple times, FutureTask is not appropriate for this purpose, although it could be useful in other cases where only a single execution is required. JavaDoc link: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/FutureTask.html – njr Aug 02 '17 at 15:39
3

Assuming you don't really need the Callable to return anything useful, you can wrap a Callable as a Runnable

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

or in Java 8

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

This is quite messy but it sounds like the Callable should have been a Runnable in the first place and you wouldn't have to do this.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
2

The JDK has a util method for exactly this:

Runnable runnable = ..
Executors.callable(runnable);
wilmol
  • 1,429
  • 16
  • 22
0

Why not use something like:

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

  Runnable callableAsRunnable = () -> {
     try {
        callable.call();
     } catch (Exception e) {
        // Handle the exception locally or throw a RuntimeException
     }
  };
Dimitar Dimitrov
  • 16,032
  • 5
  • 53
  • 55
0

Use future task , it implements both Runnable and callable , you dont need to change your code much.

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

Dave
  • 35
  • 10