Nikolai Neverov
Nikolai Neverov

Reputation: 25

Java ScheduledFuture get List

This code always returns me 10. I think that problem with receiving list of all features. I need to parse every feature and stop execution scheduler when variable limit will equals 5. How can I do this?

static int limit = 0;
static final int testNum = 10;

static ScheduledExecutorService scheduler;
public static void main(String[] args) {
    scheduler = Executors
            .newScheduledThreadPool(5);
    ScheduledFuture<Integer> future = scheduler.schedule(new ScheduledPrinter(), 10, TimeUnit.SECONDS);
    try {
        while (true) {
            System.out.println(future.get());
            if(future.get() != testNum){
                return;
            }
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}
private static class ScheduledPrinter implements Callable<Integer> {
    public Integer call() throws Exception {
        limit++;
        if(limit==5) {
            scheduler.shutdown();
            return limit;
        }
        return testNum;
    }
}

Upvotes: 1

Views: 2454

Answers (2)

Tamas Rev
Tamas Rev

Reputation: 7166

Let's see What's happening here. scheduler.schedule(new ScheduledPrinter(), 10, TimeUnit.SECONDS) runs the ScheduledPrinter.call() only once. Here is the API docs.

What you want is probably a scheduleAtFixedRate. This takes a Runnable instead of a callable, so the code will look something like this:

static volatile int limit = 0; // make it volatile because of *possible* multithreaded access
                               // an AtomicInteger would do too
static final int testNum = 10;

static ScheduledExecutorService scheduler;

public static void main(String[] args) {
    scheduler = Executors
            .newScheduledThreadPool(5);
    // discarding the future. No need to use it here.
    ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(new ScheduledPrinter(), 10L, 10L, TimeUnit.SECONDS);
}

/** Printing and counting happens here **/
private static class ScheduledPrinter implements Runnable {

    @Override
    public void run() {
        limit++;
        if(limit==5) {
            scheduler.shutdown();
            printNum(limit);
        } else {
            printNum(testNum);
        }
    }

    private void printNum(int num) {
        System.out.println(num);
    }
}

Update

OP asked how to return values from Runnable.run() method? Unfortunately, it's impossible. We have to choose between periodical run and a return value because ScheduledExecutorService cannot do both.

It's still possible to get a value out of the Runnable. We must share a reference for this. Here is a rudimentary approach:

    final Queue<Integer> numsPrinted = new ConcurrentLinkedQueue<>(); // a concurrent collection
    ScheduledFuture<?> future = scheduler.scheduleWithFixedDelay( // using scheduleWithFixedDelay because probably this is what you want
            new ScheduledPrinter(numsPrinted), // passing the reference
            10L, 10L, TimeUnit.SECONDS);
    try {
        future.isDone();
        Object obj = future.get(80, TimeUnit.SECONDS); // blocks until 80 secs or until the task is done
        System.out.println(obj);
        System.out.println(Arrays.toString(numsPrinted.toArray()));
    } catch (TimeoutException e) {
        System.out.println(Arrays.toString(numsPrinted.toArray()));
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    } 

The ScheduledPrinter now looks like this:

private static class ScheduledPrinter implements Runnable {

    private final Queue<Integer> numsPrinted;

    public ScheduledPrinter(Queue<Integer> numsPrinted) {
        this.numsPrinted = numsPrinted; // storing the reference
    }

    @Override
    public void run() {
        limit++;
        if(limit==5) {
            //scheduler.awaitTermination(timeout, unit)
            scheduler.shutdown();
            storeAndPrintNum(limit);
        } else {
            storeAndPrintNum(testNum);
        }
    }

    private void storeAndPrintNum(int num) {
        numsPrinted.add(num); // using the reference
        System.out.println(num);
    }
}

Upvotes: 2

niemar
niemar

Reputation: 642

The method ScheduledPrinter.call() is called just one time and in the while loop you always return value that was computed once. Thus limit is never incremented and shutdown is never called. So i think you need to change logic, maybe run more threads.

Upvotes: 0

Related Questions