简体   繁体   中英

How synchronize on object without locking?

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?

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.

I would put the containers in a ConcurrentLinkedQueue and have the worker threads poll the queue ie

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM