Search code examples
javamultithreadingconcurrencyjava-threads

Would locking via ReadWriteLock or synchronize(this) block a rendering thread?


Would locking via ReadWriteLock or synchronize(this) block a rendering thread?

Im writing an adapter between loader where I can't change the code, for example;

class LoaderAdapter implements Loader {

 private AnotherLoader.Callback callback = new AnotherLoader.Callback() {
   // Called on render thread
   public void onLoaded(Data data) {
     if (mData.equals(data)) {
       return;
     }

     mData = data;

     notifyListeners();
   }
 };

 private final AnotherLoader loader = ...

 private Data mData;

 // Called on render thread
 @Override
 public start() {
  loader.start();
 }


 // Called on background thread
 @Override
 public List<Items> getContent() {
   //iterate over contents
   return processor.process(mData);
 }
}

I don't think this is thread safe as mData is written to on the render thread, but reads are from a background thread.

In an attempt to fix this I added a ReadWriteLock;

class LoaderAdapter implements Loader {

 private AnotherLoader.Callback callback = new AnotherLoader.Callback() {
   // Called on render thread
   public void onLoaded(Data data) {
     lock.writeLock().lock();
     
     try {
       mData = data;
     } finally {
      lock.writelock().unlock();
     }
   }
 };

 private final AnotherLoader loader = ...
 private final ReentrantReadWriteLock lock ....

 private Data mData;

 // Called on render thread
 @Override
 public start() {
  loader.start();
 }


 // Called on background thread
 @Override
 public List<Items> getContent() {
     lock.readLock().lock();
     
     try {
       return processor.process(mData);
     } finally {
      lock.readLock().unlock();
     }
 }
}

Now the problem is onLoaded() is called on the render thread and I would be calling .lock(). Would this block the render thread and potentially slow rendering?

Is there a way to handle this, whilst working between the two classes I can't change? One option I thought of was to run the contents of onLoaded() on a BG thread to avoid locking on the render thread. However I wonder if there is a more elegant way of doing this.


Solution

  • Yes, this would block the render thread since the write lock can be acquired only if no read locks are held.

    Using a lock is overkill in this case. The solution is to declare mData volatile:

    private volatile Data mData;