Java – Avoid blocking state variable copies?

Avoid blocking state variable copies?… here is a solution to the problem.

Avoid blocking state variable copies?

I want some wisdom on my recent multithreaded ideas. Here we go :

Let’s say I have the following (pseudo) class whose run() method runs forever on some thread. Other threads will randomly use setState() to change the state of the Foo instance. The work done by run() only involves reading state variables, not writing, and the state cannot change during one execution of a while statement (e.g. drawing on a bitmap).

In this case, having 2 copies of the state variable seems to prevent a lot of potential blocking (because if I only had one copy of the shared state variable, I would have to synchronize everything in the while loop (using stateLock) and the external thread might not have a chance to change state). Problems after code breaks.

class Foo {
  Object stateLock = new Object();

private float my1, my2, my3;
  private float sh1, sh2, sh3;   sh stands for shared

public void setState(...) {
    synchronized (stateLock) {
       modify sh1, sh2, or sh3 here
    }
  }

private void updateState() {
    synchronized (stateLock) {
       set my1=sh1, my2=sh2, my3=sh3
    }
  }

public void run() {
    while(true) {
      updateState();
       then do tons of stuff that uses my1,my2,my3 over and over...
      ...
    }
  }
}

Is there any loophole in this logic? Is there a “standardized” or smarter way to do this? What if there are a large number of state variables? Even worse, what if the state variable is a custom object that is not easy to copy (for example, in java, the variable of a custom object is a reference)?

By the way, this comes to self’s current work on using SurfaceView in Android.

Solution

There is a simpler workaround:

private volatile float sh1, sh2, sh3;   note "volatile"

In the Java memory model, threads are allowed to cache values from other threads.
The volatile keyword means that all threads must use the same variable value (that is, all threads reference the same memory location of the variable). When used with primitives, this means that you do not need synchronization (although for 64-bit primitives, where float is not, you may not need to synchronize, depending on whether your JVM is 32-bit or 64-bit).

You may want to observe partial/inconsistent updates – where some sh variables are updated when another thread reads them. You may want to synchronize updates to maintain a consistent state by “atomizing” updates to multiple sh variables.

Related Problems and Solutions