1

I have seen question How do determine if an object is locked (synchronized) so not to block in Java?
But I have problem on which I can not figure out solution.
In my web application is process in which refresh of data container and that can take long time. Refresh is forced to be made in time intervals. Of course when one refresh is still on container working another cannot (to do not corrupt data in container).
I want to use background thread to refresh container. Multiple background workers can be working at the same time on multiple containers (different workers for different user sessions, every user session can have different data in their container).
Of course I can do synchronize(myContainer) in worker to force that any other worker is not currently updating this particular container. But I rather want to check if any worker is working on container and exit, if is. Also I would like to not change code of container, so I would like not to add ReentrantLock inside container class and lock on that.
So worker have MyContainer instance and want to determine if any other worker is currently refreshing this container instance.

Any ideas how to achieve that?

Community
  • 1
  • 1
Michał Herman
  • 3,437
  • 6
  • 29
  • 43

3 Answers3

2

use an AtomicBoolean, put this code in your MyContainer class:

AtomicBoolean isRefreshing = new AtomicBoolean(false);

void refresh() {
  if ( isRefreshing.compareAndSet( false, true)) {
    try {
      // refresh
    } finally {
      isRefreshing.set( false);
    }
  }
}

If you can not touch MyContainer, maybe create a RefreshWrapper holding the AtomicBoolean and the MyContainer instance.

Ralf H
  • 1,392
  • 1
  • 9
  • 17
1

I would put the containers in a ConcurrentLinkedQueue and have the worker threads poll the queue i.e.

Container container;
while((container = queue.poll()) != null) {
    container.refresh();
}

Then you have two options depending on whether the containers are tracking when they are being refreshed.

  • If they are then you can offer the refreshed containers back into the queue as soon as they're refreshed. You can use an if(container.refreshTime < X) guard to ensure that you don't refresh the container twice in the same time interval.
  • If they are not then you can either
    • Use two ConcurrentLinkedQueues and alternate between them: poll on queue1 and offer the refreshed container on queue2, and when queue1 is empty sleep until the next time interval, at which point poll on queue2 and offer the refreshed containers on queue1.
    • Or, keep an array of the containers in the main thread, and offer the containers back into the queue when the worker threads have finished refreshing all of the containers and have gone to sleep.
Zim-Zam O'Pootertoot
  • 17,888
  • 4
  • 41
  • 69
  • 1
    `ConcurrentLinkedQueue` is non-blocking which means if the OP is not careful, the while loop can do some serious busy-spinning – John Vint Jun 24 '13 at 17:23
  • @John Vint I'm assuming that the queue already holds all of the containers at the time that the worker threads are started, as would be the case if the containers are immediately re-added to the queue or are immediately added to another queue that is then alternated with the original queue. If this isn't the case then a `BlockingQueue` would be the better choice - the loop in my answer wouldn't busy-spin if containers are simultaneously added and removed from the queue, but it would run the risk of prematurely terminating. – Zim-Zam O'Pootertoot Jun 24 '13 at 17:36
  • @JohnVint: Actually, my answer has the same drawback, but I think limiting the frequency of refreshes is beyond the scope of this question, and the OP should have something in place to address that. Otherwise, a `ScheduledExecutorService` would be good solution. – Ralf H Jun 25 '13 at 10:28
0

If you need to pre-check if the object has not already been locked by some other thread, this should be possible with Thread.holdsLock method.

If this is not enough, look into the advanced lock classes. These locks provide the rich set of features (check that is waiting on the lock, try to lock with time out, lock interruptably, etc). They should provide enough features to solve your problem.

Audrius Meškauskas
  • 20,936
  • 12
  • 75
  • 93