1

I am trying to schedule a thread that wait for some condition to happen. If condition is true, return some result else again schedule itself to execute after some delay. To achieve this, I am using Executors to schedule Callable<Boolean> but it hangs after second rescheduling.

 final ExecutorService executor = Executors.newFixedThreadPool(2);
    final MutableBoolean status = new MutableBoolean(false);

    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("Waiting now to set status");
            try {
                Thread.sleep(5*1000);
                System.out.println("status is now true");
                status.setValue(true);
            } catch (InterruptedException e) {
            }

        }
    }).start();

    Future<Boolean> future = executor.submit(new Callable<Boolean>() {
        public int count=0;
        @Override
        public Boolean call() throws Exception {
            if(status.isTrue()){
                System.out.println("Condition has become true now");
                return status.booleanValue();
            } else {
                System.out.println("Not true yet, count" + count++ + " Rescheduling");
                Future<Boolean> future = executor.submit(this);
                return future.get();
            }
        }
    });

    boolean finalStatus = future.get();
    System.out.println("Final status" + finalStatus);

Output:

Waiting now to set status
Not true yet, count0 Rescheduling
Not true yet, count1 Rescheduling
status is now true

Any suggestions on what might be going wrong?

Thanks

RandomQuestion
  • 6,778
  • 17
  • 61
  • 97

2 Answers2

1

you created a thread pool of size 2. you then submit tasks to that pool from jobs running within the pool (recursively) and wait for those to complete (call future.get()).

Brett Okken
  • 6,210
  • 1
  • 19
  • 25
  • consider using a scheduled executor service to control the retrying logic. use the returned future to cancel the retry work when the condition is met. – Brett Okken Jun 03 '14 at 00:00
1

With executor.submit(this) a new task is submitted to the thread-pool each time, the thread-pool does not (and should not) check if the same task is already being executed by a thread in the thread-pool. Since the thread-pool only has two threads, both threads will be in use very quickly and waiting indefinitely.

A dirty fix is the following:

    @Override
    public Boolean call() throws Exception {
        while (true) {
            if(status.get()){
                System.out.println("Condition has become true now");
                return status.get();
            }
        }
    }

But that will cause very high CPU usage. As Brett Okken suggests, use a scheduled executor service. Or, if the status should always change to true in the near future, use a wait-barrier like CountDownLatch to react immediately to a status change.

vanOekel
  • 6,358
  • 1
  • 21
  • 56