Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread-safe but fast access to an "eventually final" variable?

I have a server somewhat like this:

class Server {

    private WorkingThing worker;

    public void init() {
         runInNewThread({
             // this will take about a minute
             worker = new WorkingThing();
         });
    }

    public Response handleRequest(Request req) {
         if (worker == null) throw new IllegalStateException("Not inited yet");
         return worker.work(req);
    }

}

As you can see, there are threads handling requests and a thread initing the server. Requests can come in before initing has finished, therefore there is the check with an IllegalStateException.

Now, to make this thread safe (so request handler threads don't see a stale, null-valued, version of worker just after init), I'd have to make worker volatile, synchronize on it, or some such.

However, after the init has completed, worker won't ever change again, so it's effectively final. Therefore, it seems like any lock contention that may occur would be a waste. So, what's the most efficient thing I can do here?

Now I know it doesn't really matter in a practical sense (with all the heavy lifting of reading a network request, etc, what does a single lock matter?), but I'd like to know out of curiosity.

like image 209
Bart van Heukelom Avatar asked Aug 09 '13 08:08

Bart van Heukelom


1 Answers

A note on volatile: marking a variable volatile is cheaper than using synchronization (it does not involve locks) and is generally cheap enough that you won't notice. In particular, on x86 architectures, reading a volatile variable does not cost more than reading a non-volatile variable. However writing to a volatile is more expensive and the fact that the variable is volatile might prevent some compiler optimisations.

So using volatile is probably the option that gives you the best performance/complexity ratio in your scenario.

You don't have that many alternatives. In the end it boils down to ensuring a safe publication of your worker. And safe publication idioms include:

  • initialising the instance from a static initialiser
  • marking the reference to the instance as final
  • marking the reference to the instance as volatile
  • synchronizing all accesses

In your case, only the last two options are available and using volatile is more efficient.

like image 53
assylias Avatar answered Oct 02 '22 07:10

assylias