1

My problem is we have to give it a fixed schedule time to make it start task. Lets say i give 10 seconds and my task has average finish time of 10-15 seconds. Thus after some time waiting threads in quque causes huge memory consumption. If i use syncronized for the method above problem will occur. If i don't use syncronized then i am wasting resources ( cpu) because i dont need to run task if not finished. So i thought a solution of recursive call of task but i believe recursive threads will add more memory problems... what should i do? Shortly i just want to be able to call a task when it is finished. Not fixed time.

public void myScheduledTask{
    doJob(); ( use countdown latch to control waiting if necessary)
    TimeUnit.SECONDS.sleep(x);
    new Thread( new Runnable( { mySchedulTask();   } ));
    or
    executor.execute( a thread that call myScheduledTask() method);
}
xingbin
  • 27,410
  • 9
  • 53
  • 103
  • If the tasks need to be limited on one at a time, then use a scheduled thread pool with one thread for those tasks. – Jim Garrison Jan 19 '18 at 06:22
  • I dont quite get what you mean. Can you elaborate in more detail? Thanks – Mert Serimer Alumni Jan 19 '18 at 06:23
  • Don't over complicate things, It's a simple case of, if you add more than you subtract then you will certainly accumulate a blockage of threads. Not using synchronised in such circumstances is not a fix or work around, you are only setting yourself up for trouble down the track. You need to use a ThreadPoolExecutor in my opinion. Why are you against using such a beast? – Matt G Jan 19 '18 at 06:32
  • @Mat i just want to be able to call a task when it is finished. Not fixed time. – Mert Serimer Alumni Jan 19 '18 at 06:34
  • @MertSerimerAlumni buyurun abi, does this help: https://stackoverflow.com/questions/826212/java-executors-how-to-be-notified-without-blocking-when-a-task-completes – Matt G Jan 19 '18 at 06:38
  • @Mat thanks but i know how to wait for itself finish by using countdownlatch but the problem is i want to solve this non recursive ways. All i desire is not fixed scheduleservice =) – Mert Serimer Alumni Jan 19 '18 at 08:20
  • Your question is quite unclear. If you just want to execute tasks one after the other, create an executor with only one thread, and submit your tasks to that executor. It will execute them one after the other. – JB Nizet Jan 19 '18 at 08:23
  • @JBNizet it has to be scheduled but conditional scheduled depending on when previous task finishes. – Mert Serimer Alumni Jan 19 '18 at 08:25
  • That's unclear. Elaborate. Give a concrete example. – JB Nizet Jan 19 '18 at 08:26
  • What about [ScheduledExecutorService#scheduleWithFixedDelay](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html#scheduleWithFixedDelay-java.lang.Runnable-long-long-java.util.concurrent.TimeUnit-) that way, after your task completes it will way for the same delay to restart it. – matt Jan 19 '18 at 08:58
  • @matt scheduledexecutor waits every task to finish to start? Are you sure? Then no point of sync – Mert Serimer Alumni Jan 19 '18 at 12:46
  • How do you mean, wait for every task? Your example has one task, that you want to execute at a fixed delay. If you have two tasks you can submit those, and it will try to execute them at their own schedule rates. If your pool size is 1 only one task will run at a time. – matt Jan 19 '18 at 12:49

2 Answers2

2

The option that sounds like what you're trying to accomplish:

ScheduledExecutorService executor = Executors.newScheduledThreadPool(count);
ScheduledFuture<?> future = executor.scheduleWithFixedDelay(
                                   task, 
                                   delay, 
                                   delay, 
                                   TimeUnit.MILLISECONDS
                                  );

This would start your task and execute it after delay milliseconds after the previous completion. Count should be the number of threads you want to use, 1 is acceptable. This also lets you stop the task using the future.

The problems with your example. a) You are sleeping on an executor thread. Dont do this let the executor handle it. If you were using a threadpool of 1 then this executor couldn't do any work while you're waiting. b) Starting a new thread is taking control from the executor... just use the executor, then you have some control over the execution.

If you really wanted to stick with the form you have.

class RecurringTask implements Runnable{
    @Override
    public void run(){
        doJob();
        executor.schedule(this, delay, TimeUnit.MILLISECONDS); 
    }
}

Now you will be creating Futures that you never use, so it will be harder to control the execution of the task.

matt
  • 10,892
  • 3
  • 22
  • 34
  • Does executor always wait for current thread to finish to start new one? – Mert Serimer Alumni Jan 19 '18 at 12:47
  • Why do you care if it starts a new thread? It will perform the execution of the tasks you submit according to resources and how you submit them. – matt Jan 19 '18 at 12:50
  • it is waste because i dont want new info until the current one comes. Plus if it starts before it finishes then sub threads will be created more than it should ( cpu core count ) etc – Mert Serimer Alumni Jan 19 '18 at 12:53
  • First off, it handles threads. Done, don't talk about creating new threads. You set the number of threads when you create the service. That is what the variable `count` does. If you schedule a task to happen with a fixed delay, that task will never be running at the same time. The run method will be called, after it finishes the the executor will wait for `delay` milliseconds then start the task again. – matt Jan 19 '18 at 12:56
  • thanks it ensures task will be finished before it starts new one. – Mert Serimer Alumni Jan 19 '18 at 13:03
0

Create static member in your task class - Lock. In doJob avoid performing job if lock is already aquired :

 if (lock.tryLock()) {
      try {
          // do the job
      } finally {
          lock.unlock();
      }
  } else {
      // log the fact you skipped the job
      return;
  }
Alexander Anikin
  • 1,108
  • 6
  • 14
  • Do you think this would be different than using synchronized to protect the resource? – matt Jan 19 '18 at 11:37
  • 1
    Yes, next attempt is skipped (not delayed) if current one is still working. Most obvious effect: you will never get many locked threads waiting for resource. It's not appropriate for every scenario, since there is no guaranteed number of actual jobDone "meat" executions. But it's ok for maintenance tasks started externally - i.e. by Quartz. – Alexander Anikin Jan 19 '18 at 13:31