I’d like some wisdom regarding a recent multithreading idea of mine. Here goes:
Suppose I have the following (pseudo) class whose run() method is chugging away forever on some thread. Other threads will at random times change the state of the Foo instance using setState(). The work that run() is doing only involves reading the state variables, no writing, and the state must not change during one execution of the while statement (example: drawing on a bitmap).
In this case, having 2 copies of the state variables seems to prevent a lot of potential blocking (since if I only had one copy of shared state variables, I would have to synchronize everything in the while loop (using stateLock) and outside threads may not get the chance to change the state). Questions after the code break.
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...
...
}
}
}
Any holes in this logic? Is there a “standardized” or smarter way of doing this? What if there are tons of state variables? Worse, what if state variables are custom objects that don’t copy easily (e.g. in java where variables of custom objects are references)?
By the way, this comes from my current work with a SurfaceView in Android.
To keep all the variables in sync and to avoid synchronization, you can put the variables inside an immutable object and update it as a whole. When reading the state, keep hold of one such state object as local variable, and you will be guaranteed that nobody else updates it while you are reading it.
Here is some sample code (not tested etc.). If the old values are not read in
setStateor it is accessed only from one thread, then a volatile field would be enough. But in the general case (multiple threads calling setState and the new state depends on the value of the old state), using AtomicReference makes sure that the no updates will be missed.Here is sample code for the special case that updating the state does not depend on the old values of the state: