adarsh srivastava
adarsh srivastava

Reputation: 25

How to execute a @Scheduled job in a thread safe manner in SpringBoot?

I have a service class that adds elements to a set and there is a scheduled job method that executes after every 2 seconds which reads all the elements added to the set (the one in which service adds elements) and at the end, it clears the whole set.

I am confused if some element gets added to the list between I am reading the data from the set or between the time after I am done reading data from the set and before clearing the set then that element will be lost.

How can I make sure no element gets added to the set while the scheduled job is not finished?

EventService.java


public void foo(){
    eventSet.add(new Event("event description"));
}

EventJob.java

@Autowired
EventService eventService;

@Scheduled(cron = "${cron.expression.for.every.2.second}")
private void job(){
    for(Event event : eventService.getEventSet()){
         //process event
         System.out.println(event);
    }
    eventService.getEventSet().clear();
}

Upvotes: 0

Views: 859

Answers (3)

rifat cakir
rifat cakir

Reputation: 61

As my understanding, you can create a thread control for this behavior,

private static ReentrantLock listLock = new ReentrantLock();

  private void readSomeData() {
    // Get the lock of object
    listLock.lock();

    // read list

    // free the lock
    listLock.unlock();
  }

  @Scheduled(cron = "${cron.expression.for.every.2.second}")
  private void job() {
    // Check lock is free or not
    if (!listLock.isLocked()) {
      // Get the lock of object
      listLock.lock();
      for (Event event : eventService.getEventSet()) {
        // process event
        System.out.println(event);
      }
      eventService.getEventSet().clear();
    }
    // free the lock
    listLock.unlock();
  }

Upvotes: 1

Ricardo
Ricardo

Reputation: 409

You should be aware that if you are in a multiple machine cluster other problems will arise that will not be solved by this "in-memory" solution.

private AtomicBoolean isRunning = new AtomicBoolean(false);

public void job(){
     Set<YourObject> events = eventService.getEventSet();
     if (isRunning.compareAndSet(false, true)) {
        for(Event event : events){
            //process event
        }
       
        eventService.getEventSet().clear();
        isRunning.compareAndSet(true, false);
     }
     
}

Edited after op clarification!

Upvotes: 0

Hakuna Matata
Hakuna Matata

Reputation: 761

If you don't want to be added to the set while running the scheduled job means you have to maintain some flags based on some set limits and enable that AtomicBoolean to true when the when you reached the limit "false" once you have cleared the set. Below is the pseudo code,

AtomicBoolean canAddData = new AtomicBoolean(true);

public void foo(){
    if(canAddData){ // here instead of atomicboolean you can use eventSet.size()==10 as well if you want to be added based on some level size.
      eventSet.add(new Event("event description"));
      canAddData.set(eventSet.size() <= 10)
   }
}

// scheduler code 
public void processEvents() {
     Iterator<Event> eventIter = eventSet.iterator()
     while(eventIterator.hasNext()) {
          Event = eventIterator.remove()
          // Process event here and clearing item one by one
     }
     canAddData.set(true)
}

Upvotes: 0

Related Questions